Snapshots

This commit is contained in:
Luis Fernando Molina committed 2020-05-10 14:17:33 +02:00
1 parent e91125801d
commit 6368221937
75 files changed
+8943 -4332

No files matched your search

+23 -1
View File
@@ -333,9 +333,21 @@ function exportKeywordsToPackageJson (exchanges) {
// ----------------------------------------------------------------------------
function exportEverything () {
function flatten (nested, result = []) {
for (const key in nested) {
result.push (key)
if (Object.keys (nested[key]).length)
flatten (nested[key], result)
}
return result
}
function exportEverything () {
const ids = getIncludedExchangeIds ()
const errorHierarchy = require ('../js/base/errorHierarchy.js')
const flat = flatten (errorHierarchy)
flat.push ('error_hierarchy')
const replacements = [
{
@@ -353,6 +365,16 @@ function exportEverything () {
regex: /(?:from ccxt\.[^\.]+ import [^\s]+\s+\# noqa\: F401[\r]?[\n])+[\r]?[\n]exchanges/,
replacement: ids.map (id => ('from ccxt.' + id + ' import ' + id).padEnd (60) + '# noqa: F401').join ("\n") + "\n\nexchanges",
},
{
file: './python/ccxt/__init__.py',
regex: /(?:from ccxt\.base\.errors import [^\s]+\s+\# noqa\: F401[\r]?[\n])+[\r]?[\n]/,
replacement: flat.map (error => ('from ccxt.base.errors' + ' import ' + error).padEnd (60) + '# noqa: F401').join ("\n") + "\n\n",
},
{
file: './python/ccxt/async_support/__init__.py',
regex: /(?:from ccxt\.base\.errors import [^\s]+\s+\# noqa\: F401[\r]?[\n])+[\r]?[\n]/,
replacement: flat.map (error => ('from ccxt.base.errors' + ' import ' + error).padEnd (60) + '# noqa: F401').join ("\n") + "\n\n",
},
{
file: './python/ccxt/async_support/__init__.py',
regex: /(?:from ccxt\.async_support\.[^\.]+ import [^\s]+\s+\# noqa\: F401[\r]?[\n])+[\r]?[\n]exchanges/,
+2
View File
@@ -199,6 +199,7 @@ class Transpiler {
[ /(^|[^a-zA-Z0-9_])(?:let|const|var)\s/g, '$1' ],
[ /Object\.keys\s*\((.*)\)\.length/g, '$1' ],
[ /Object\.keys\s*\((.*)\)/g, 'list($1.keys())' ],
[ /Object\.values\s*\((.*)\)/g, 'list($1.values())' ],
[ /\[([^\]]+)\]\.join\s*\(([^\)]+)\)/g, "$2.join([$1])" ],
[ /hash \(([^,]+)\, \'(sha[0-9])\'/g, "hash($1, '$2'" ],
[ /hmac \(([^,]+)\, ([^,]+)\, \'(md5)\'/g, 'hmac($1, $2, hashlib.$3' ],
@@ -330,6 +331,7 @@ class Transpiler {
[ /(^|[^a-zA-Z0-9_])(?:let|const|var)\s/g, '$1' ],
[ /Object\.keys\s*\((.*)\)\.length/g, '$1' ],
[ /Object\.keys\s*\((.*)\)/g, 'is_array($1) ? array_keys($1) : array()' ],
[ /Object\.values\s*\((.*)\)/g, 'is_array($1) ? array_values($1) : array()' ],
[ /([^\s]+\s*\(\))\.toString \(\)/g, '(string) $1' ],
[ /([^\s]+)\.toString \(\)/g, '(string) $1' ],
[ /throw new Error \((.*)\)/g, 'throw new \\Exception($1)' ],
+2 -3
View File
@@ -35,7 +35,7 @@ const Exchange = require ('./js/base/Exchange')
//-----------------------------------------------------------------------------
// this is updated by vss.js when building
const version = '1.25.80'
const version = '1.27.45'
Exchange.ccxtVersion = version
@@ -44,7 +44,6 @@ Exchange.ccxtVersion = version
const exchanges = {
'_1btcxe': require ('./js/_1btcxe.js'),
'acx': require ('./js/acx.js'),
'adara': require ('./js/adara.js'),
'anxpro': require ('./js/anxpro.js'),
'aofex': require ('./js/aofex.js'),
'bcex': require ('./js/bcex.js'),
@@ -115,8 +114,8 @@ const exchanges = {
'fybse': require ('./js/fybse.js'),
'gateio': require ('./js/gateio.js'),
'gemini': require ('./js/gemini.js'),
'hbtc': require ('./js/hbtc.js'),
'hitbtc': require ('./js/hitbtc.js'),
'hitbtc2': require ('./js/hitbtc2.js'),
'hollaex': require ('./js/hollaex.js'),
'huobipro': require ('./js/huobipro.js'),
'huobiru': require ('./js/huobiru.js'),
+4395 -2136
View File
File diff suppressed because it is too large. Load diff
-1255
View File
File diff suppressed because it is too large. Load diff
+9 -3
View File
@@ -30,6 +30,7 @@ module.exports = class aofex extends Exchange {
'fetchOpenOrders': true,
'fetchClosedOrders': true,
'fetchClosedOrder': true,
'fetchOrderTrades': true,
'fetchTradingFee': true,
},
'timeframes': {
@@ -559,7 +560,7 @@ module.exports = class aofex extends Exchange {
//
const id = this.safeString (trade, 'id');
const ctime = this.parse8601 (this.safeString (trade, 'ctime'));
const timestamp = this.safeTimestamp (trade, 'ts', ctime);
const timestamp = this.safeTimestamp (trade, 'ts', ctime) - 28800000; // 8 hours, adjust to UTC;
let symbol = undefined;
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
@@ -725,7 +726,7 @@ module.exports = class aofex extends Exchange {
base = market['base'];
quote = market['quote'];
}
const timestamp = this.parse8601 (this.safeString (order, 'ctime'));
const timestamp = this.parse8601 (this.safeString (order, 'ctime')) - 28800000; // 8 hours, adjust to UTC
const orderType = this.safeString (order, 'type');
const type = (orderType === '2') ? 'limit' : 'market';
const side = this.safeString (order, 'side');
@@ -883,11 +884,16 @@ module.exports = class aofex extends Exchange {
return this.parseOrder (order);
}
async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
const response = await this.fetchClosedOrder (id, symbol, params);
return this.safeValue (response, 'trades', []);
}
async fetchOrdersWithMethod (method, symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {
// 'from': 'BM7442641584965237751ZMAKJ5', // query start order_sn
// 'direct': 'prev', // next
'direct': 'prev', // next
};
let market = undefined;
if (symbol !== undefined) {
+43 -15
View File
@@ -288,8 +288,9 @@ module.exports = class Exchange {
const config = deepExtend (this.describe (), userConfig)
// merge to this
for (const [property, value] of Object.entries (config))
for (const [property, value] of Object.entries (config)) {
this[property] = deepExtend (this[property], value)
}
if (!this.httpAgent) {
this.httpAgent = defaultFetch.http ? new defaultFetch.http.Agent ({ 'keepAlive': true }) : undefined
@@ -304,13 +305,15 @@ module.exports = class Exchange {
this['has' + capitalize (k)] = !!this.has[k] // converts 'emulated' to true
}
if (this.api)
if (this.api) {
this.defineRestApi (this.api, 'request')
}
this.initRestRateLimiter ()
if (this.markets)
if (this.markets) {
this.setMarkets (this.markets)
}
}
defaults () {
@@ -342,20 +345,23 @@ module.exports = class Exchange {
checkAddress (address) {
if (address === undefined)
if (address === undefined) {
throw new InvalidAddress (this.id + ' address is undefined')
}
// check the address is not the same letter like 'aaaaa' nor too short nor has a space
if ((unique (address).length === 1) || address.length < this.minFundingAddressLength || address.includes (' '))
if ((unique (address).length === 1) || address.length < this.minFundingAddressLength || address.includes (' ')) {
throw new InvalidAddress (this.id + ' address is invalid or has less than ' + this.minFundingAddressLength.toString () + ' characters: "' + this.json (address) + '"')
}
return address
}
initRestRateLimiter () {
if (this.rateLimit === undefined)
if (this.rateLimit === undefined) {
throw new Error (this.id + '.rateLimit property is not configured')
}
this.tokenBucket = this.extend ({
delay: 1,
@@ -386,15 +392,17 @@ module.exports = class Exchange {
const promise =
fetchImplementation (url, this.extend (params, this.fetchOptions))
.catch ((e) => {
if (isNode)
if (isNode) {
throw new ExchangeNotAvailable ([ this.id, method, url, e.type, e.message ].join (' '))
}
throw e // rethrow all unknown errors
})
.then (response => this.handleRestResponse (response, url, method, headers, body))
.then ((response) => this.handleRestResponse (response, url, method, headers, body))
return timeout (this.timeout, promise).catch ((e) => {
if (e instanceof TimedOut)
if (e instanceof TimedOut) {
throw new RequestTimeout (this.id + ' ' + method + ' ' + url + ' request timed out (' + this.timeout + ' ms)')
}
throw e
})
}
@@ -442,16 +450,20 @@ module.exports = class Exchange {
let underscore = type + '_' + lowercaseMethod + '_' + underscoreSuffix
if ('suffixes' in options) {
if ('camelcase' in options['suffixes'])
if ('camelcase' in options['suffixes']) {
camelcase += options['suffixes']['camelcase']
if ('underscore' in options.suffixes)
}
if ('underscore' in options.suffixes) {
underscore += options['suffixes']['underscore']
}
}
if ('underscore_suffix' in options)
if ('underscore_suffix' in options) {
underscore += options.underscoreSuffix;
if ('camelcase_suffix' in options)
}
if ('camelcase_suffix' in options) {
camelcase += options.camelcaseSuffix;
}
let partial = async params => this[methodName] (path, type, uppercaseMethod, params || {})
@@ -594,7 +606,7 @@ module.exports = class Exchange {
getResponseHeaders (response) {
const result = {}
response.headers.forEach ((value, key) => {
key = key.split ('-').map (word => capitalize (word)).join ('-')
key = key.split ('-').map ((word) => capitalize (word)).join ('-')
result[key] = value
})
return result
@@ -632,7 +644,7 @@ module.exports = class Exchange {
}
setMarkets (markets, currencies = undefined) {
const values = Object.values (markets).map (market => deepExtend ({
const values = Object.values (markets).map ((market) => deepExtend ({
'limits': this.limits,
'precision': this.precision,
}, this.fees['trading'], market))
@@ -803,6 +815,22 @@ module.exports = class Exchange {
throw new NotSupported (this.id + ' fetchOrder not supported yet');
}
fetchUnifiedOrder (order, params = {}) {
return this.fetchOrder (this.safeValue (order, 'id'), this.safeValue (order, 'symbol'), params);
}
createOrder (symbol, type, side, amount, price = undefined, params = {}) {
throw new NotSupported (this.id + ' createOrder not supported yet');
}
cancelOrder (id, symbol = undefined, params = {}) {
throw new NotSupported (this.id + ' cancelOrder not supported yet');
}
cancelUnifiedOrder (order, params = {}) {
return this.cancelOrder (this.safeValue (order, 'id'), this.safeValue (order, 'symbol'), params);
}
fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
throw new NotSupported (this.id + ' fetchOrders not supported yet');
}
+11 -7
View File
@@ -45,23 +45,27 @@ function numberToString (x) { // avoids scientific notation for too large and to
if (typeof x === 'string') return x
const s = x.toString ()
if (Math.abs (x) < 1.0) {
const s = x.toString ()
const e = parseInt (s.split ('e-')[1])
const neg = (s[0] === '-')
if (e) {
x *= Math.pow (10, e - 1)
x = (neg ? '-' : '') + '0.' + (new Array (e)).join ('0') + x.toString ().substring (neg ? 3 : 2)
return x
}
} else {
let e = parseInt (x.toString ().split ('+')[1])
if (e > 20) {
e -= 20
x /= Math.pow (10, e)
x += (new Array (e + 1)).join ('0')
const parts = s.split ('e')
if (parts[1]) {
let e = parseInt (parts[1])
const m = parts[0].split ('.')
if (m[1]) {
e -= m[1].length
}
return m[0] + m[1] + (new Array (e + 1)).join ('0')
}
}
return x.toString ()
return s;
}
//-----------------------------------------------------------------------------
+106 -34
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied } = require ('./base/errors');
const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied, NotSupported } = require ('./base/errors');
const { ROUND, TRUNCATE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -37,6 +37,7 @@ module.exports = class binance extends Exchange {
'fetchTransactions': false,
'fetchTradingFee': true,
'fetchTradingFees': true,
'cancelAllOrders': true,
},
'timeframes': {
'1m': '1m',
@@ -57,6 +58,10 @@ module.exports = class binance extends Exchange {
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/29604020-d5483cdc-87ee-11e7-94c7-d1a8d9169293.jpg',
'test': {
'fapiPublic': 'https://testnet.binancefuture.com/fapi/v1',
'fapiPrivate': 'https://testnet.binancefuture.com/fapi/v1',
},
'api': {
'web': 'https://www.binance.com',
'wapi': 'https://api.binance.com/wapi/v3',
@@ -130,6 +135,8 @@ module.exports = class binance extends Exchange {
'lending/union/purchaseRecord',
'lending/union/redemptionRecord',
'lending/union/interestHistory',
'lending/project/list',
'lending/project/position/list',
],
'post': [
'asset/dust',
@@ -146,6 +153,7 @@ module.exports = class binance extends Exchange {
'userDataStream',
'futures/transfer',
// lending
'lending/customizedFixed/purchase',
'lending/daily/purchase',
'lending/daily/redeem',
],
@@ -211,6 +219,8 @@ module.exports = class binance extends Exchange {
'income',
],
'post': [
'batchOrders',
'positionSide/dual',
'positionMargin',
'marginType',
'order',
@@ -221,6 +231,7 @@ module.exports = class binance extends Exchange {
'listenKey',
],
'delete': [
'batchOrders',
'order',
'allOpenOrders',
'listenKey',
@@ -267,6 +278,7 @@ module.exports = class binance extends Exchange {
'order/test',
],
'delete': [
'openOrders', // added on 2020-04-25 for canceling all open orders per symbol
'orderList', // oco
'order',
],
@@ -289,7 +301,6 @@ module.exports = class binance extends Exchange {
'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades
'fetchTickersMethod': 'publicGetTicker24hr',
'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
'defaultLimitOrderType': 'limit', // or 'limit_maker'
'defaultType': 'spot', // 'spot', 'future'
'hasAlreadyAuthenticatedSuccessfully': false,
'warnOnFetchOpenOrdersWithoutSymbol': true,
@@ -326,6 +337,32 @@ module.exports = class binance extends Exchange {
});
}
setSandboxMode (enabled) {
if (enabled) { // eslint-disable-line no-extra-boolean-cast
if ('test' in this.urls) {
const type = this.safeString (this.options, 'defaultType', 'spot');
if (type !== 'future') {
throw new NotSupported (this.id + ' does not have a sandbox URL for ' + type + " markets, set exchange.options['defaultType'] = 'future' or don't use the sandbox for " + this.id);
}
if (typeof this.urls['api'] === 'string') {
this.urls['api_backup'] = this.urls['api'];
this.urls['api'] = this.urls['test'];
} else {
this.urls['api_backup'] = this.extend ({}, this.urls['api']);
this.urls['api'] = this.extend ({}, this.urls['test']);
}
} else {
throw new NotSupported (this.id + ' does not have a sandbox URL');
}
} else if ('api_backup' in this.urls) {
if (typeof this.urls['api'] === 'string') {
this.urls['api'] = this.urls['api_backup'];
} else {
this.urls['api'] = this.extend ({}, this.urls['api_backup']);
}
}
}
nonce () {
return this.milliseconds () - this.options['timeDifference'];
}
@@ -476,7 +513,7 @@ module.exports = class binance extends Exchange {
'max': undefined,
},
'cost': {
'min': -1 * Math.log10 (precision['amount']),
'min': undefined,
'max': undefined,
},
},
@@ -720,7 +757,7 @@ module.exports = class binance extends Exchange {
async fetchBidsAsks (symbols = undefined, params = {}) {
await this.loadMarkets ();
const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', 'spot');
const defaultType = this.safeString2 (this.options, 'fetchBidsAsks', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
const method = (type === 'spot') ? 'publicGetTickerBookTicker' : 'fapiPublicGetTickerBookTicker';
@@ -737,12 +774,12 @@ module.exports = class binance extends Exchange {
parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
return [
ohlcv[0],
parseFloat (ohlcv[1]),
parseFloat (ohlcv[2]),
parseFloat (ohlcv[3]),
parseFloat (ohlcv[4]),
parseFloat (ohlcv[5]),
this.safeInteger (ohlcv, 0),
this.safeFloat (ohlcv, 1),
this.safeFloat (ohlcv, 2),
this.safeFloat (ohlcv, 3),
this.safeFloat (ohlcv, 4),
this.safeFloat (ohlcv, 5),
];
}
@@ -870,6 +907,10 @@ module.exports = class binance extends Exchange {
if (market !== undefined) {
symbol = market['symbol'];
}
let cost = undefined;
if ((price !== undefined) && (amount !== undefined)) {
cost = price * amount;
}
return {
'info': trade,
'timestamp': timestamp,
@@ -878,11 +919,11 @@ module.exports = class binance extends Exchange {
'id': id,
'order': orderId,
'type': undefined,
'takerOrMaker': takerOrMaker,
'side': side,
'takerOrMaker': takerOrMaker,
'price': price,
'amount': amount,
'cost': price * amount,
'cost': cost,
'fee': fee,
};
}
@@ -1180,6 +1221,8 @@ module.exports = class binance extends Exchange {
} else if (uppercaseType === 'STOP') {
stopPriceIsRequired = true;
priceIsRequired = true;
} else if (uppercaseType === 'STOP_MARKET') {
stopPriceIsRequired = true;
}
if (priceIsRequired) {
if (price === undefined) {
@@ -1339,6 +1382,27 @@ module.exports = class binance extends Exchange {
return this.parseOrder (response);
}
async cancelAllOrders (symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' cancelAllOrders requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
const defaultType = this.safeString2 (this.options, 'cancelAllOrders', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
const method = (type === 'spot') ? 'privateDeleteOpenOrders' : 'fapiPrivateDeleteAllOpenOrders';
const response = await this[method] (this.extend (request, query));
if (Array.isArray (response)) {
return this.parseOrders (response, market);
} else {
return response;
}
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
@@ -1571,10 +1635,7 @@ module.exports = class binance extends Exchange {
}
parseTransactionStatusByType (status, type = undefined) {
if (type === undefined) {
return status;
}
const statuses = {
const statusesByType = {
'deposit': {
'0': 'pending',
'1': 'ok',
@@ -1589,32 +1650,38 @@ module.exports = class binance extends Exchange {
'6': 'ok', // Completed
},
};
return (status in statuses[type]) ? statuses[type][status] : status;
const statuses = this.safeValue (statusesByType, type, {});
return this.safeString (statuses, status, status);
}
parseTransaction (transaction, currency = undefined) {
//
// fetchDeposits
// { insertTime: 1517425007000,
// amount: 0.3,
// address: "0x0123456789abcdef",
// addressTag: "",
// txId: "0x0123456789abcdef",
// asset: "ETH",
// status: 1 }
//
// {
// insertTime: 1517425007000,
// amount: 0.3,
// address: "0x0123456789abcdef",
// addressTag: "",
// txId: "0x0123456789abcdef",
// asset: "ETH",
// status: 1
// }
//
// fetchWithdrawals
//
// { amount: 14,
// address: "0x0123456789abcdef...",
// {
// amount: 14,
// address: "0x0123456789abcdef...",
// successTime: 1514489710000,
// transactionFee: 0.01,
// addressTag: "",
// txId: "0x0123456789abcdef...",
// id: "0123456789abcdef...",
// asset: "ETH",
// applyTime: 1514488724000,
// status: 6 }
// transactionFee: 0.01,
// addressTag: "",
// txId: "0x0123456789abcdef...",
// id: "0123456789abcdef...",
// asset: "ETH",
// applyTime: 1514488724000,
// status: 6
// }
//
const id = this.safeString (transaction, 'id');
const address = this.safeString (transaction, 'address');
@@ -1624,7 +1691,7 @@ module.exports = class binance extends Exchange {
tag = undefined;
}
}
const txid = this.safeValue (transaction, 'txId');
const txid = this.safeString (transaction, 'txId');
const currencyId = this.safeString (transaction, 'asset');
const code = this.safeCurrencyCode (currencyId, currency);
let timestamp = undefined;
@@ -1854,6 +1921,11 @@ module.exports = class binance extends Exchange {
'timestamp': this.nonce (),
'recvWindow': this.options['recvWindow'],
}, params));
} else if (path === 'batchOrders') {
query = this.rawencode (this.extend ({
'timestamp': this.nonce (),
'recvWindow': this.options['recvWindow'],
}, params));
} else {
query = this.urlencode (this.extend ({
'timestamp': this.nonce (),
+3 -3
View File
@@ -31,10 +31,10 @@ module.exports = class binanceus extends binance {
},
'fees': {
'trading': {
'tierBased': false,
'tierBased': true,
'percentage': true,
'taker': 0.0, // 0.1% trading fee, zero fees for all trading pairs before November 1
'maker': 0.0, // 0.1% trading fee, zero fees for all trading pairs before November 1
'taker': 0.001, // 0.1% trading fee, zero fees for all trading pairs before November 1
'maker': 0.001, // 0.1% trading fee, zero fees for all trading pairs before November 1
},
},
});
+67 -2
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded } = require ('./base/errors');
const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded, OnMaintenance } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -53,6 +53,7 @@ module.exports = class bitbay extends Exchange {
'https://github.com/BitBayNet/API',
'https://docs.bitbay.net/v1.0.1-en/reference',
],
'support': 'https://support.bitbay.net',
'fees': 'https://bitbay.net/en/fees',
},
'api': {
@@ -117,8 +118,60 @@ module.exports = class bitbay extends Exchange {
},
'fees': {
'trading': {
'maker': 0.0,
'taker': 0.1 / 100,
'percentage': true,
'tierBased': false,
},
'fiat': {
'maker': 0.30 / 100,
'taker': 0.43 / 100,
'percentage': true,
'tierBased': true,
'tiers': {
'taker': [
[ 0.0043, 0 ],
[ 0.0042, 1250 ],
[ 0.0041, 3750 ],
[ 0.0040, 7500 ],
[ 0.0039, 10000 ],
[ 0.0038, 15000 ],
[ 0.0037, 20000 ],
[ 0.0036, 25000 ],
[ 0.0035, 37500 ],
[ 0.0034, 50000 ],
[ 0.0033, 75000 ],
[ 0.0032, 100000 ],
[ 0.0031, 150000 ],
[ 0.0030, 200000 ],
[ 0.0029, 250000 ],
[ 0.0028, 375000 ],
[ 0.0027, 500000 ],
[ 0.0026, 625000 ],
[ 0.0025, 875000 ],
],
'maker': [
[ 0.0030, 0 ],
[ 0.0029, 1250 ],
[ 0.0028, 3750 ],
[ 0.0028, 7500 ],
[ 0.0027, 10000 ],
[ 0.0026, 15000 ],
[ 0.0025, 20000 ],
[ 0.0025, 25000 ],
[ 0.0024, 37500 ],
[ 0.0023, 50000 ],
[ 0.0023, 75000 ],
[ 0.0022, 100000 ],
[ 0.0021, 150000 ],
[ 0.0021, 200000 ],
[ 0.0020, 250000 ],
[ 0.0019, 375000 ],
[ 0.0018, 500000 ],
[ 0.0018, 625000 ],
[ 0.0017, 875000 ],
],
},
},
'funding': {
'withdraw': {
@@ -135,6 +188,9 @@ module.exports = class bitbay extends Exchange {
},
},
},
'options': {
'fiatCurrencies': [ 'EUR', 'USD', 'GBP', 'PLN' ],
},
'exceptions': {
'400': ExchangeError, // At least one parameter wasn't set
'401': InvalidOrder, // Invalid order type
@@ -159,12 +215,14 @@ module.exports = class bitbay extends Exchange {
'OFFER_NOT_FOUND': OrderNotFound,
'OFFER_WOULD_HAVE_BEEN_PARTIALLY_FILLED': OrderImmediatelyFillable,
'ACTION_LIMIT_EXCEEDED': RateLimitExceeded,
'UNDER_MAINTENANCE': OnMaintenance,
},
});
}
async fetchMarkets (params = {}) {
const response = await this.v1_01PublicGetTradingTicker (params);
const fiatCurrencies = this.safeValue (this.options, 'fiatCurrencies', []);
//
// {
// status: 'Ok',
@@ -203,6 +261,12 @@ module.exports = class bitbay extends Exchange {
'amount': this.safeInteger (first, 'scale'),
'price': this.safeInteger (second, 'scale'),
};
let fees = this.safeValue (this.fees, 'trading', {});
if (this.inArray (base, fiatCurrencies) || this.inArray (quote, fiatCurrencies)) {
fees = this.safeValue (this.fees, 'fiat', {});
}
const maker = this.safeFloat (fees, 'maker');
const taker = this.safeFloat (fees, 'taker');
// todo: check that the limits have ben interpreted correctly
// todo: parse the fees page
result.push ({
@@ -214,7 +278,8 @@ module.exports = class bitbay extends Exchange {
'quoteId': quoteId,
'precision': precision,
'active': undefined,
'fee': undefined,
'maker': maker,
'taker': taker,
'limits': {
'amount': {
'min': this.safeFloat (first, 'minOffer'),
+6 -6
View File
@@ -905,12 +905,12 @@ module.exports = class bitfinex extends Exchange {
parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
return [
ohlcv[0],
ohlcv[1],
ohlcv[3],
ohlcv[4],
ohlcv[2],
ohlcv[5],
this.safeInteger (ohlcv, 0),
this.safeFloat (ohlcv, 1),
this.safeFloat (ohlcv, 3),
this.safeFloat (ohlcv, 4),
this.safeFloat (ohlcv, 2),
this.safeFloat (ohlcv, 5),
];
}
+1
View File
@@ -699,6 +699,7 @@ module.exports = class bitfinex2 extends bitfinex {
'PARTIALLY FILLED': 'open',
'EXECUTED': 'closed',
'CANCELED': 'canceled',
'CANCELED was: PARTIALLY FILLED': 'canceled',
'INSUFFICIENT MARGIN': 'canceled',
'INSUFFICIENT BALANCE (G1) was: PARTIALLY FILLED': 'canceled',
'RSN_DUST': 'rejected',
+393 -44
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, ExchangeNotAvailable, AuthenticationError, BadRequest, PermissionDenied, InvalidAddress } = require ('./base/errors');
const { ExchangeError, ExchangeNotAvailable, AuthenticationError, BadRequest, PermissionDenied, InvalidAddress, ArgumentsRequired, InvalidOrder } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -16,7 +16,12 @@ module.exports = class bithumb extends Exchange {
'rateLimit': 500,
'has': {
'CORS': true,
'createOrder': true,
'cancelOrder': true,
'createMarketOrder': true,
'fetchTickers': true,
'fetchOpenOrders': true,
'fetchOrder': true,
'withdraw': true,
},
'urls': {
@@ -48,8 +53,8 @@ module.exports = class bithumb extends Exchange {
'info/ticker',
'info/orders',
'info/user_transactions',
'trade/place',
'info/order_detail',
'trade/place',
'trade/cancel',
'trade/btc_withdrawal',
'trade/krw_deposit',
@@ -165,15 +170,53 @@ module.exports = class bithumb extends Exchange {
'currency': market['base'],
};
if (limit !== undefined) {
request['count'] = limit; // max = 50
request['count'] = limit; // default 30, max 30
}
const response = await this.publicGetOrderbookCurrency (this.extend (request, params));
const orderbook = this.safeValue (response, 'data');
const timestamp = this.safeInteger (orderbook, 'timestamp');
return this.parseOrderBook (orderbook, timestamp, 'bids', 'asks', 'price', 'quantity');
//
// {
// "status":"0000",
// "data":{
// "timestamp":"1587621553942",
// "payment_currency":"KRW",
// "order_currency":"BTC",
// "bids":[
// {"price":"8652000","quantity":"0.0043"},
// {"price":"8651000","quantity":"0.0049"},
// {"price":"8650000","quantity":"8.4791"},
// ],
// "asks":[
// {"price":"8654000","quantity":"0.119"},
// {"price":"8655000","quantity":"0.254"},
// {"price":"8658000","quantity":"0.119"},
// ]
// }
// }
//
const data = this.safeValue (response, 'data', {});
const timestamp = this.safeInteger (data, 'timestamp');
return this.parseOrderBook (data, timestamp, 'bids', 'asks', 'price', 'quantity');
}
parseTicker (ticker, market = undefined) {
//
// fetchTicker, fetchTickers
//
// {
// "opening_price":"227100",
// "closing_price":"228400",
// "min_price":"222300",
// "max_price":"230000",
// "units_traded":"82618.56075337",
// "acc_trade_value":"18767376138.6031",
// "prev_closing_price":"227100",
// "units_traded_24H":"151871.13484676",
// "acc_trade_value_24H":"34247610416.8974",
// "fluctate_24H":"8700",
// "fluctate_rate_24H":"3.96",
// "date":"1587710327264", // fetchTickers inject this
// }
//
const timestamp = this.safeInteger (ticker, 'date');
let symbol = undefined;
if (market !== undefined) {
@@ -224,9 +267,31 @@ module.exports = class bithumb extends Exchange {
async fetchTickers (symbols = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.publicGetTickerAll (params);
//
// {
// "status":"0000",
// "data":{
// "BTC":{
// "opening_price":"9045000",
// "closing_price":"9132000",
// "min_price":"8938000",
// "max_price":"9168000",
// "units_traded":"4619.79967497",
// "acc_trade_value":"42021363832.5187",
// "prev_closing_price":"9041000",
// "units_traded_24H":"8793.5045804",
// "acc_trade_value_24H":"78933458515.4962",
// "fluctate_24H":"530000",
// "fluctate_rate_24H":"6.16"
// },
// "date":"1587710878669"
// }
// }
//
const result = {};
const timestamp = this.safeInteger (response['data'], 'date');
const tickers = this.omit (response['data'], 'date');
const data = this.safeValue (response, 'data', {});
const timestamp = this.safeInteger (data, 'date');
const tickers = this.omit (data, 'date');
const ids = Object.keys (tickers);
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
@@ -253,19 +318,72 @@ module.exports = class bithumb extends Exchange {
'currency': market['base'],
};
const response = await this.publicGetTickerCurrency (this.extend (request, params));
return this.parseTicker (response['data'], market);
//
// {
// "status":"0000",
// "data":{
// "opening_price":"227100",
// "closing_price":"228400",
// "min_price":"222300",
// "max_price":"230000",
// "units_traded":"82618.56075337",
// "acc_trade_value":"18767376138.6031",
// "prev_closing_price":"227100",
// "units_traded_24H":"151871.13484676",
// "acc_trade_value_24H":"34247610416.8974",
// "fluctate_24H":"8700",
// "fluctate_rate_24H":"3.96",
// "date":"1587710327264"
// }
// }
//
const data = this.safeValue (response, 'data', {});
return this.parseTicker (data, market);
}
parseTrade (trade, market = undefined) {
//
// fetchTrades (public)
//
// {
// "transaction_date":"2020-04-23 22:21:46",
// "type":"ask",
// "units_traded":"0.0125",
// "price":"8667000",
// "total":"108337"
// }
//
// fetchOrder (private)
//
// {
// "transaction_date": "1572497603902030",
// "price": "8601000",
// "units": "0.005",
// "fee_currency": "KRW",
// "fee": "107.51",
// "total": "43005"
// }
//
// a workaround for their bug in date format, hours are not 0-padded
const parts = trade['transaction_date'].split (' ');
const transaction_date = parts[0];
let transaction_time = parts[1];
if (transaction_time.length < 8) {
transaction_time = '0' + transaction_time;
let timestamp = undefined;
const transactionDatetime = this.safeString (trade, 'transaction_date');
if (transactionDatetime !== undefined) {
const parts = transactionDatetime.split (' ');
const numParts = parts.length;
if (numParts > 1) {
const transactionDate = parts[0];
let transactionTime = parts[1];
if (transactionTime.length < 8) {
transactionTime = '0' + transactionTime;
}
timestamp = this.parse8601 (transactionDate + ' ' + transactionTime);
} else {
timestamp = this.safeIntegerProduct (trade, 'transaction_date', 0.001);
}
}
if (timestamp !== undefined) {
timestamp -= 9 * 3600000; // they report UTC + 9 hours, server in Korean timezone
}
let timestamp = this.parse8601 (transaction_date + ' ' + transaction_time);
timestamp -= 9 * 3600000; // they report UTC + 9 hours (server in Korean timezone)
const type = undefined;
let side = this.safeString (trade, 'type');
side = (side === 'ask') ? 'sell' : 'buy';
@@ -276,12 +394,24 @@ module.exports = class bithumb extends Exchange {
}
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'units_traded');
let cost = undefined;
if (amount !== undefined) {
if (price !== undefined) {
cost = price * amount;
let cost = this.safeFloat (trade, 'total');
if (cost === undefined) {
if (amount !== undefined) {
if (price !== undefined) {
cost = price * amount;
}
}
}
let fee = undefined;
const feeCost = this.safeFloat (trade, 'fee');
if (feeCost !== undefined) {
const feeCurrencyId = this.safeString (trade, 'fee_currency');
const feeCurrencyCode = this.commonCurrencyCode (feeCurrencyId);
fee = {
'cost': feeCost,
'currency': feeCurrencyCode,
};
}
return {
'id': id,
'info': trade,
@@ -295,7 +425,7 @@ module.exports = class bithumb extends Exchange {
'price': price,
'amount': amount,
'cost': cost,
'fee': undefined,
'fee': fee,
};
}
@@ -309,57 +439,276 @@ module.exports = class bithumb extends Exchange {
request['count'] = limit; // default 20, max 100
}
const response = await this.publicGetTransactionHistoryCurrency (this.extend (request, params));
return this.parseTrades (response['data'], market, since, limit);
//
// {
// "status":"0000",
// "data":[
// {
// "transaction_date":"2020-04-23 22:21:46",
// "type":"ask",
// "units_traded":"0.0125",
// "price":"8667000",
// "total":"108337"
// },
// ]
// }
//
const data = this.safeValue (response, 'data', []);
return this.parseTrades (data, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
let request = undefined;
let method = 'privatePostTrade';
const request = {
'order_currency': market['id'],
'Payment_currency': market['quote'],
'units': amount,
};
let method = 'privatePostTradePlace';
if (type === 'limit') {
request = {
'order_currency': market['id'],
'Payment_currency': market['quote'],
'units': amount,
'price': price,
'type': (side === 'buy') ? 'bid' : 'ask',
};
method += 'Place';
} else if (type === 'market') {
request = {
'currency': market['id'],
'units': amount,
};
method += 'Market' + this.capitalize (side);
request['price'] = price;
request['type'] = (side === 'buy') ? 'bid' : 'ask';
} else {
method = 'privatePostTradeMarket' + this.capitalize (side);
}
const response = await this[method] (this.extend (request, params));
const id = this.safeString (response, 'order_id');
if (id === undefined) {
throw new InvalidOrder (this.id + ' createOrder did not return an order id');
}
return {
'info': response,
'symbol': symbol,
'type': type,
'side': side,
'id': id,
};
}
async fetchOrder (id, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'order_id': id,
'count': 1,
'order_currency': market['base'],
'payment_currency': market['quote'],
};
const response = await this.privatePostInfoOrderDetail (this.extend (request, params));
//
// {
// "status": "0000",
// "data": {
// "transaction_date": "1572497603668315",
// "type": "bid",
// "order_status": "Completed",
// "order_currency": "BTC",
// "payment_currency": "KRW",
// "order_price": "8601000",
// "order_qty": "0.007",
// "cancel_date": "",
// "cancel_type": "",
// "contract": [
// {
// "transaction_date": "1572497603902030",
// "price": "8601000",
// "units": "0.005",
// "fee_currency": "KRW",
// "fee": "107.51",
// "total": "43005"
// },
// ]
// }
// }
//
const data = this.safeValue (response, 'data');
return this.parseOrder (this.extend (data, { 'order_id': id }), market);
}
parseOrderStatus (status) {
const statuses = {
'Pending': 'open',
'Completed': 'closed',
'Cancel': 'canceled',
};
return this.safeString (statuses, status, status);
}
parseOrder (order, market = undefined) {
//
// fetchOrder
//
// {
// "transaction_date": "1572497603668315",
// "type": "bid",
// "order_status": "Completed",
// "order_currency": "BTC",
// "payment_currency": "KRW",
// "order_price": "8601000",
// "order_qty": "0.007",
// "cancel_date": "",
// "cancel_type": "",
// "contract": [
// {
// "transaction_date": "1572497603902030",
// "price": "8601000",
// "units": "0.005",
// "fee_currency": "KRW",
// "fee": "107.51",
// "total": "43005"
// },
// ]
// }
//
// fetchOpenOrders
//
// {
// "order_currency": "BTC",
// "payment_currency": "KRW",
// "order_id": "C0101000007408440032",
// "order_date": "1571728739360570",
// "type": "bid",
// "units": "5.0",
// "units_remaining": "5.0",
// "price": "501000",
// }
//
const timestamp = this.safeIntegerProduct (order, 'order_date', 0.001);
const sideProperty = this.safeValue2 (order, 'type', 'side');
const side = (sideProperty === 'bid') ? 'buy' : 'sell';
const status = this.parseOrderStatus (this.safeString (order, 'order_status'));
let price = this.safeFloat2 (order, 'order_price', 'price');
let type = 'limit';
if (price === 0) {
price = undefined;
type = 'market';
}
const amount = this.safeFloat2 (order, 'order_qty', 'units');
let remaining = this.safeFloat (order, 'units_remaining');
if (remaining === undefined) {
if (status === 'closed') {
remaining = 0;
} else {
remaining = amount;
}
}
let filled = undefined;
if ((amount !== undefined) && (remaining !== undefined)) {
filled = amount - remaining;
}
let symbol = undefined;
const baseId = this.safeString (order, 'order_currency');
const quoteId = this.safeString (order, 'payment_currency');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
if ((base !== undefined) && (quote !== undefined)) {
symbol = base + '/' + quote;
}
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
const rawTrades = this.safeValue (order, 'contract');
let trades = undefined;
const id = this.safeString (order, 'order_id');
if (rawTrades !== undefined) {
trades = this.parseTrades (rawTrades, market, undefined, undefined, {
'side': side,
'symbol': symbol,
'order': id,
});
}
return {
'info': order,
'id': id,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
'side': side,
'price': price,
'amount': amount,
'cost': undefined,
'average': undefined,
'filled': filled,
'remaining': remaining,
'status': status,
'fee': undefined,
'trades': trades,
};
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
if (limit === undefined) {
limit = 100;
}
const request = {
'count': limit,
'order_currency': market['base'],
'payment_currency': market['quote'],
};
if (since !== undefined) {
request['after'] = since;
}
const response = await this.privatePostInfoOrders (this.extend (request, params));
//
// {
// "status": "0000",
// "data": [
// {
// "order_currency": "BTC",
// "payment_currency": "KRW",
// "order_id": "C0101000007408440032",
// "order_date": "1571728739360570",
// "type": "bid",
// "units": "5.0",
// "units_remaining": "5.0",
// "price": "501000",
// }
// ]
// }
//
const data = this.safeValue (response, 'data', []);
return this.parseOrders (data, market, since, limit);
}
async cancelOrder (id, symbol = undefined, params = {}) {
const side_in_params = ('side' in params);
if (!side_in_params) {
throw new ExchangeError (this.id + ' cancelOrder requires a `side` parameter (sell or buy) and a `currency` parameter');
throw new ArgumentsRequired (this.id + ' cancelOrder requires a `symbol` argument and a `side` parameter (sell or buy)');
}
const currency = this.safeString (params, 'currency');
if (currency === undefined) {
throw new ExchangeError (this.id + ' cancelOrder requires a `currency` parameter (a currency id)');
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' cancelOrder requires a `symbol` argument and a `side` parameter (sell or buy)');
}
const market = this.market (symbol);
const side = (params['side'] === 'buy') ? 'bid' : 'ask';
params = this.omit (params, [ 'side', 'currency' ]);
// https://github.com/ccxt/ccxt/issues/6771
const request = {
'order_id': id,
'type': side,
'currency': currency,
'order_currency': market['base'],
'payment_currency': market['quote'],
};
return await this.privatePostTradeCancel (this.extend (request, params));
}
cancelUnifiedOrder (order, params = {}) {
const request = {
'side': order['side'],
};
return this.cancelOrder (order['id'], order['symbol'], this.extend (request, params));
}
async withdraw (code, amount, address, tag = undefined, params = {}) {
this.checkAddress (address);
await this.loadMarkets ();
@@ -372,7 +721,7 @@ module.exports = class bithumb extends Exchange {
if (currency === 'XRP' || currency === 'XMR') {
const destination = this.safeString (params, 'destination');
if ((tag === undefined) && (destination === undefined)) {
throw new ExchangeError (this.id + ' ' + code + ' withdraw() requires a tag argument or an extra destination param');
throw new ArgumentsRequired (this.id + ' ' + code + ' withdraw() requires a tag argument or an extra destination param');
} else if (tag !== undefined) {
request['destination'] = tag;
}
+2
View File
@@ -35,6 +35,7 @@ module.exports = class bitmart extends Exchange {
'fetchClosedOrders': true,
'fetchCanceledOrders': true,
'fetchOrder': true,
'signIn': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/61835713-a2662f80-ae85-11e9-9d00-6442919701fd.jpg',
@@ -42,6 +43,7 @@ module.exports = class bitmart extends Exchange {
'www': 'https://www.bitmart.com/',
'doc': 'https://github.com/bitmartexchange/bitmart-official-api-docs',
'referral': 'http://www.bitmart.com/?r=rQCFLh',
'fees': 'https://www.bitmart.com/fee/en',
},
'requiredCredentials': {
'apiKey': true,
+9 -1
View File
@@ -1134,11 +1134,19 @@ module.exports = class bitstamp extends Exchange {
body = this.urlencode (query);
contentType = 'application/x-www-form-urlencoded';
headers['Content-Type'] = contentType;
} else {
// sending an empty POST request will trigger
// an API0020 error returned by the exchange
// therefore for empty requests we send a dummy object
// https://github.com/ccxt/ccxt/issues/6846
body = this.urlencode ({ 'foo': 'bar' });
contentType = 'application/x-www-form-urlencoded';
headers['Content-Type'] = contentType;
}
}
const authBody = body ? body : '';
const auth = xAuth + method + url.replace ('https://', '') + contentType + xAuthNonce + xAuthTimestamp + xAuthVersion + authBody;
const signature = this.encode (this.hmac (this.encode (auth), this.encode (this.secret)));
const signature = this.hmac (this.encode (auth), this.encode (this.secret));
headers['X-Auth-Signature'] = signature;
}
}
+1 -1
View File
@@ -650,7 +650,7 @@ module.exports = class bitz extends Exchange {
}
} else {
if (since !== undefined) {
throw new ExchangeError (this.id + ' fetchOHLCV requires a limit argument if the since argument is specified');
throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a limit argument if the since argument is specified');
}
}
const response = await this.marketGetKline (this.extend (request, params));
+5 -2
View File
@@ -73,6 +73,9 @@ module.exports = class bleutrade extends Exchange {
],
},
'v3Private': {
'get': [
'statement',
],
'post': [
'getbalance',
'getbalances',
@@ -189,8 +192,8 @@ module.exports = class bleutrade extends Exchange {
// MarketCurrencyLong: 'Litecoin',
// BaseCurrencyLong: 'Tether' }
const id = this.safeString (market, 'MarketName');
const baseId = this.safeString (market, 'MarketCurrency');
const quoteId = this.safeString (market, 'BaseCurrency');
const baseId = this.safeString (market, 'MarketAsset');
const quoteId = this.safeString (market, 'BaseAsset');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
+1
View File
@@ -18,6 +18,7 @@ module.exports = class btctradeua extends Exchange {
'CORS': false,
'createMarketOrder': false,
'fetchOpenOrders': true,
'signIn': true,
},
'urls': {
'referral': 'https://btc-trade.com.ua/registration/22689',
+3 -3
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { AddressPending, AuthenticationError, ExchangeError, NotSupported, PermissionDenied } = require ('./base/errors');
const { AddressPending, AuthenticationError, ExchangeError, NotSupported, PermissionDenied, ArgumentsRequired } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -692,7 +692,7 @@ module.exports = class buda extends Exchange {
async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
if (code === undefined) {
throw new ExchangeError (this.id + ': fetchDeposits() requires a currency code argument');
throw new ArgumentsRequired (this.id + ': fetchDeposits() requires a currency code argument');
}
const currency = this.currency (code);
const request = {
@@ -707,7 +707,7 @@ module.exports = class buda extends Exchange {
async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
if (code === undefined) {
throw new ExchangeError (this.id + ': fetchDeposits() requires a currency code argument');
throw new ArgumentsRequired (this.id + ': fetchDeposits() requires a currency code argument');
}
const currency = this.currency (code);
const request = {
+220 -57
View File
@@ -4,7 +4,7 @@
const Exchange = require ('./base/Exchange');
const { TICK_SIZE } = require ('./base/functions/number');
const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce } = require ('./base/errors');
const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce, NotSupported } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -48,7 +48,7 @@ module.exports = class bybit extends Exchange {
'30m': '30',
'1h': '60',
'2h': '120',
'3h': '180',
'4h': '240',
'6h': '360',
'12h': '720',
'1d': 'D',
@@ -63,6 +63,7 @@ module.exports = class bybit extends Exchange {
'www': 'https://www.bybit.com/',
'doc': [
'https://bybit-exchange.github.io/docs/inverse/',
'https://bybit-exchange.github.io/docs/linear/',
'https://github.com/bybit-exchange',
],
'fees': 'https://help.bybit.com/hc/en-us/articles/360039261154',
@@ -116,6 +117,41 @@ module.exports = class bybit extends Exchange {
'position/trading-stop',
],
},
'publicLinear': {
'get': [
'kline',
'recent-trading-records',
'funding/prev-funding-rate',
'mark-price-kline',
],
},
'privateLinear': {
'get': [
'order/list',
'order/search',
'stop-order/list',
'stop-order/search',
'position/list',
'position/set-auto-add-margin',
'position/set-leverage',
'position/switch-isolated',
'position/trading-stop',
'position/add-margin',
'trade/execution/list',
'trade/closed-pnl/list',
'risk-limit',
'funding/prev-funding',
'funding/predicted-funding',
],
'post': [
'order/create',
'order/cancel',
'order/cancelAll',
'stop-order/create',
'stop-order/cancel',
'stop-order/cancelAll',
],
},
'position': {
'post': [
'change-position-margin',
@@ -227,6 +263,9 @@ module.exports = class bybit extends Exchange {
},
'precisionMode': TICK_SIZE,
'options': {
'marketTypes': {
'BTC/USDT': 'linear',
},
'code': 'BTC',
'fetchBalance': {
'code': 'BTC',
@@ -309,6 +348,8 @@ module.exports = class bybit extends Exchange {
// }
//
const markets = this.safeValue (response, 'result', []);
const options = this.safeValue (this.options, 'fetchMarkets', {});
const linearQuoteCurrencies = this.safeValue (options, 'linear', { 'USDT': true });
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
@@ -317,6 +358,8 @@ module.exports = class bybit extends Exchange {
const quoteId = this.safeString (market, 'quote_currency');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const linear = (quote in linearQuoteCurrencies);
const inverse = !linear;
const symbol = base + '/' + quote;
const lotSizeFilter = this.safeValue (market, 'lot_size_filter', {});
const priceFilter = this.safeValue (market, 'price_filter', {});
@@ -333,6 +376,12 @@ module.exports = class bybit extends Exchange {
'precision': precision,
'taker': this.safeFloat (market, 'taker_fee'),
'maker': this.safeFloat (market, 'maker_fee'),
'type': 'future',
'spot': false,
'future': true,
'option': false,
'linear': linear,
'inverse': inverse,
'limits': {
'amount': {
'min': this.safeFloat (lotSizeFilter, 'min_trading_qty'),
@@ -347,10 +396,6 @@ module.exports = class bybit extends Exchange {
'max': undefined,
},
},
'type': 'future',
'spot': false,
'future': true,
'option': false,
'info': market,
});
}
@@ -610,13 +655,25 @@ module.exports = class bybit extends Exchange {
// turnover: '162.32773718999994'
// },
//
// {
// "id":143536,
// "symbol":"BTCUSDT",
// "period":"15",
// "start_at":1587883500,
// "volume":1.035,
// "open":7540.5,
// "high":7541,
// "low":7540.5,
// "close":7541
// }
//
return [
this.safeTimestamp (ohlcv, 'open_time'),
this.safeTimestamp2 (ohlcv, 'open_time', 'start_at'),
this.safeFloat (ohlcv, 'open'),
this.safeFloat (ohlcv, 'high'),
this.safeFloat (ohlcv, 'low'),
this.safeFloat (ohlcv, 'close'),
this.safeFloat (ohlcv, 'turnover'),
this.safeFloat2 (ohlcv, 'turnover', 'volume'),
];
}
@@ -641,7 +698,13 @@ module.exports = class bybit extends Exchange {
if (limit !== undefined) {
request['limit'] = limit; // max 200, default 200
}
const response = await this.publicGetKlineList (this.extend (request, params));
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
const method = (marketType === 'linear') ? 'publicLinearGetKline' : 'publicGetKlineList';
const response = await this[method] (this.extend (request, params));
//
// inverse perpetual BTC/USD
//
// {
// ret_code: 0,
// ret_msg: 'OK',
@@ -662,6 +725,30 @@ module.exports = class bybit extends Exchange {
// ],
// time_now: '1583953082.397330'
// }
//
// linear perpetual BTC/USDT
//
// {
// "ret_code":0,
// "ret_msg":"OK",
// "ext_code":"",
// "ext_info":"",
// "result":[
// {
// "id":143536,
// "symbol":"BTCUSDT",
// "period":"15",
// "start_at":1587883500,
// "volume":1.035,
// "open":7540.5,
// "high":7541,
// "low":7540.5,
// "close":7541
// }
// ],
// "time_now":"1587884120.168077"
// }
//
const result = this.safeValue (response, 'result', {});
return this.parseOHLCVs (result, market, timeframe, since, limit);
}
@@ -688,6 +775,8 @@ module.exports = class bybit extends Exchange {
// "exec_id": "256e5ef8-abfe-5772-971b-f944e15e0d68",
// "exec_price": "8178.5",
// "exec_qty": 1,
// // the docs say the exec_time field is "abandoned" now
// // the user should use "trade_time_ms"
// "exec_time": "1571676941.70682",
// "exec_type": "Trade", //Exec Type Enum
// "exec_value": "0.00012227",
@@ -702,30 +791,35 @@ module.exports = class bybit extends Exchange {
// "order_type": "Market", //Order Type Enum
// "side": "Buy", //Side Enum
// "symbol": "BTCUSD", //Symbol Enum
// "user_id": 1
// "user_id": 1,
// "trade_time_ms": 1577480599000
// }
//
const id = this.safeString2 (trade, 'id', 'exec_id');
let symbol = undefined;
let base = undefined;
const marketId = this.safeString (trade, 'symbol');
let amount = this.safeFloat2 (trade, 'qty', 'exec_qty');
let cost = this.safeFloat (trade, 'exec_value');
const price = this.safeFloat2 (trade, 'price', 'exec_price');
if (marketId in this.markets_by_id) {
market = this.markets_by_id[marketId];
symbol = market['symbol'];
base = market['base'];
}
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
base = market['base'];
if (market !== undefined) {
if (symbol === undefined) {
symbol = market['symbol'];
base = market['base'];
}
// if private trade
if ('exec_fee' in trade) {
if (market['inverse']) {
amount = this.safeFloat (trade, 'exec_value');
cost = this.safeFloat (trade, 'exec_qty');
}
}
}
let timestamp = this.parse8601 (this.safeString (trade, 'time'));
if (timestamp === undefined) {
timestamp = this.safeTimestamp (trade, 'exec_time');
}
const side = this.safeStringLower (trade, 'side');
const price = this.safeFloat2 (trade, 'price', 'exec_price');
const amount = this.safeFloat2 (trade, 'qty', 'exec_qty');
let cost = this.safeFloat (trade, 'exec_value');
if (cost === undefined) {
if (amount !== undefined) {
if (price !== undefined) {
@@ -733,6 +827,11 @@ module.exports = class bybit extends Exchange {
}
}
}
let timestamp = this.parse8601 (this.safeString (trade, 'time'));
if (timestamp === undefined) {
timestamp = this.safeInteger (trade, 'trade_time_ms');
}
const side = this.safeStringLower (trade, 'side');
const lastLiquidityInd = this.safeString (trade, 'last_liquidity_ind');
const takerOrMaker = (lastLiquidityInd === 'AddedLiquidity') ? 'maker' : 'taker';
const feeCost = this.safeFloat (trade, 'exec_fee');
@@ -771,7 +870,10 @@ module.exports = class bybit extends Exchange {
if (limit !== undefined) {
request['count'] = limit; // default 500, max 1000
}
const response = await this.publicGetTradingRecords (this.extend (request, params));
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
const method = (marketType === 'linear') ? 'publicLinearGetRecentTradingRecords' : 'publicGetTradingRecords';
const response = await this[method] (this.extend (request, params));
//
// {
// ret_code: 0,
@@ -885,8 +987,8 @@ module.exports = class bybit extends Exchange {
// "last_exec_time": 0,
// "last_exec_price": 0,
// "leaves_qty": 1,
// "cum_exec_qty": 0,
// "cum_exec_value": 0,
// "cum_exec_qty": 0, // in contracts, where 1 contract = 1 quote currency unit (USD for inverse contracts)
// "cum_exec_value": 0, // in contract's underlying currency (BTC for inverse contracts)
// "cum_exec_fee": 0,
// "reject_reason": "",
// "order_link_id": "",
@@ -894,18 +996,69 @@ module.exports = class bybit extends Exchange {
// "updated_at": "2019-11-30T11:03:43.455Z"
// }
//
// fetchOrder
//
// {
// "user_id" : 599946,
// "symbol" : "BTCUSD",
// "side" : "Buy",
// "order_type" : "Limit",
// "price" : "7948",
// "qty" : 10,
// "time_in_force" : "GoodTillCancel",
// "order_status" : "Filled",
// "ext_fields" : {
// "o_req_num" : -1600687220498,
// "xreq_type" : "x_create"
// },
// "last_exec_time" : "1588150113.968422",
// "last_exec_price" : "7948",
// "leaves_qty" : 0,
// "leaves_value" : "0",
// "cum_exec_qty" : 10,
// "cum_exec_value" : "0.00125817",
// "cum_exec_fee" : "-0.00000031",
// "reject_reason" : "",
// "cancel_type" : "",
// "order_link_id" : "",
// "created_at" : "2020-04-29T08:45:24.399146Z",
// "updated_at" : "2020-04-29T08:48:33.968422Z",
// "order_id" : "dd2504b9-0157-406a-99e1-efa522373944"
// }
//
const marketId = this.safeString (order, 'symbol');
let symbol = undefined;
let base = undefined;
if (marketId in this.markets_by_id) {
market = this.markets_by_id[marketId];
}
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const id = this.safeString (order, 'order_id');
const price = this.safeFloat (order, 'price');
const average = this.safeFloat (order, 'average_price');
const amount = this.safeFloat (order, 'qty');
let filled = this.safeFloat (order, 'cum_exec_qty');
let remaining = this.safeFloat (order, 'leaves_qty');
let amount = undefined;
let cost = undefined;
let filled = undefined;
let remaining = undefined;
if (market !== undefined) {
symbol = market['symbol'];
base = market['base'];
if (market['inverse']) {
cost = this.safeFloat (order, 'cum_exec_qty');
filled = this.safeFloat (order, 'cum_exec_value');
remaining = this.safeFloat (order, 'leaves_value');
amount = this.sum (filled, remaining);
} else {
amount = this.safeFloat (order, 'qty');
cost = this.safeFloat (order, 'cum_exec_value');
filled = this.safeFloat (order, 'cum_exec_qty');
remaining = this.safeFloat (order, 'leaves_qty');
}
}
let lastTradeTimestamp = this.safeTimestamp (order, 'last_exec_time');
if (lastTradeTimestamp === 0) {
lastTradeTimestamp = undefined;
}
let cost = this.safeFloat (order, 'cum_exec_value');
if ((filled === undefined) && (amount !== undefined) && (remaining !== undefined)) {
filled = amount - remaining;
}
@@ -920,22 +1073,6 @@ module.exports = class bybit extends Exchange {
}
}
const status = this.parseOrderStatus (this.safeString (order, 'order_status'));
const marketId = this.safeString (order, 'symbol');
let symbol = undefined;
let base = undefined;
if (marketId in this.markets_by_id) {
market = this.markets_by_id[marketId];
symbol = market['symbol'];
base = market['base'];
}
if (market !== undefined) {
if (symbol === undefined) {
symbol = market['symbol'];
}
if (base === undefined) {
base = market['base'];
}
}
const side = this.safeStringLower (order, 'side');
let feeCost = this.safeFloat (order, 'cum_exec_fee');
let fee = undefined;
@@ -987,7 +1124,9 @@ module.exports = class bybit extends Exchange {
// conditional orders ---------------------------------------------
// 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders
};
let method = 'privateGetOrder';
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
let method = (marketType === 'linear') ? 'privateLinearGetOrderSearch' : 'privateGetOrder';
const stopOrderId = this.safeString (params, 'stop_order_id');
if (stopOrderId === undefined) {
const orderLinkId = this.safeString (params, 'order_link_id');
@@ -995,7 +1134,7 @@ module.exports = class bybit extends Exchange {
request['order_id'] = id;
}
} else {
method = 'privateGetStopOrder';
method = (marketType === 'linear') ? 'privateLinearGetStopOrderSearch' : 'privateGetStopOrder';
}
const response = await this[method] (this.extend (request, params));
//
@@ -1107,12 +1246,14 @@ module.exports = class bybit extends Exchange {
}
const stopPx = this.safeValue (params, 'stop_px');
const basePrice = this.safeValue (params, 'base_price');
let method = 'privatePostOrderCreate';
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
let method = (marketType === 'linear') ? 'privateLinearPostOrderCreate' : 'privatePostOrderCreate';
if (stopPx !== undefined) {
if (basePrice === undefined) {
throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order');
} else {
method = 'openapiPostStopOrderCreate';
method = (marketType === 'linear') ? 'privateLinearPostStopOrderCreate' : 'openapiPostStopOrderCreate';
request['stop_px'] = this.priceToPrecision (symbol, stopPx);
request['base_price'] = this.priceToPrecision (symbol, basePrice);
params = this.omit (params, [ 'stop_px', 'base_price' ]);
@@ -1206,6 +1347,11 @@ module.exports = class bybit extends Exchange {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' editOrder requires an symbol argument');
}
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
if (marketType === 'linear') {
throw new NotSupported (this.id + ' does not support editOrder for ' + marketType + ' ' + symbol + ' market type');
}
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
@@ -1283,7 +1429,9 @@ module.exports = class bybit extends Exchange {
// conditional orders ---------------------------------------------
// 'stop_order_id': id, // one of stop_order_id or order_link_id is required for conditional orders
};
let method = 'privatePostOrderCancel';
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeValue (marketTypes, symbol);
let method = (marketType === 'linear') ? 'privateLinearPostOrderCancel' : 'privatePostOrderCancel';
const stopOrderId = this.safeString (params, 'stop_order_id');
if (stopOrderId === undefined) {
const orderLinkId = this.safeString (params, 'order_link_id');
@@ -1291,7 +1439,7 @@ module.exports = class bybit extends Exchange {
request['order_id'] = id;
}
} else {
method = 'openapiPostStopOrderCancel';
method = (marketType === 'linear') ? 'privateLinearPostStopOrderCancel' : 'openapiPostStopOrderCancel';
}
const response = await this[method] (this.extend (request, params));
const result = this.safeValue (response, 'result', {});
@@ -1308,7 +1456,10 @@ module.exports = class bybit extends Exchange {
'symbol': market['id'],
};
const options = this.safeValue (this.options, 'cancelAllOrders');
const method = this.safeString (options, 'method', 'privatePostOrderCancelAll');
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
const defaultMethod = (marketType === 'linear') ? 'privateLinearPostOrderCancelAll' : 'privatePostOrderCancelAll';
const method = this.safeString (options, 'method', defaultMethod);
const response = await this[method] (this.extend (request, params));
const result = this.safeValue (response, 'result', []);
return this.parseOrders (result, market);
@@ -1337,7 +1488,9 @@ module.exports = class bybit extends Exchange {
request['limit'] = limit;
}
const options = this.safeValue (this.options, 'fetchOrders', {});
let defaultMethod = 'openapiGetOrderList';
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
let defaultMethod = (marketType === 'linear') ? 'privateLinearGetOrderList' : 'openapiGetOrderList';
let query = params;
if (('stop_order_id' in params) || ('stop_order_status' in params)) {
let stopOrderStatus = this.safeValue (params, 'stopOrderStatus');
@@ -1348,7 +1501,7 @@ module.exports = class bybit extends Exchange {
request['stop_order_status'] = stopOrderStatus;
query = this.omit (params, 'stop_order_status');
}
defaultMethod = 'openapiGetStopOrderList';
defaultMethod = (marketType === 'linear') ? 'privateLinearGetStopOrderList' : 'openapiGetStopOrderList';
}
const method = this.safeString (options, 'method', defaultMethod);
const response = await this[method] (this.extend (request, query));
@@ -1524,12 +1677,15 @@ module.exports = class bybit extends Exchange {
request['symbol'] = market['id'];
}
if (since !== undefined) {
request['start_time'] = parseInt (since / 1000);
request['start_time'] = since;
}
if (limit !== undefined) {
request['limit'] = limit; // default 20, max 50
}
const response = await this.privateGetExecutionList (this.extend (request, params));
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
const method = (marketType === 'linear') ? 'privateLinearGetTradeExecutionList' : 'privateGetExecutionList';
const response = await this[method] (this.extend (request, params));
//
// {
// "ret_code": 0,
@@ -1864,6 +2020,11 @@ module.exports = class bybit extends Exchange {
if (Object.keys (params).length) {
request += '?' + this.rawencode (params);
}
} else if (api === 'publicLinear') {
request = '/public/linear/' + request;
if (Object.keys (params).length) {
request += '?' + this.rawencode (params);
}
} else {
this.checkRequiredCredentials ();
if (api === 'openapi') {
@@ -1871,14 +2032,16 @@ module.exports = class bybit extends Exchange {
} else if (api === 'private') {
// private v2
request = '/' + this.version + '/' + api + '/' + request;
} else if (api === 'privateLinear') {
request = '/private/linear/' + request;
} else {
// position, user
request += '/' + api + '/' + request;
request = '/' + api + '/' + request;
}
const timestamp = this.nonce ();
const query = this.extend (params, {
'api_key': this.apiKey,
'recvWindow': this.options['recvWindow'],
'recv_window': this.options['recvWindow'],
'timestamp': timestamp,
});
const auth = this.rawencode (this.keysort (query));
+11 -5
View File
@@ -47,9 +47,15 @@ module.exports = class bytetrade extends Exchange {
'1M': '1M',
},
'urls': {
'test': 'https://api-v2-test.byte-trade.com',
'test': {
'market': 'https://api-v2-test.byte-trade.com',
'public': 'https://api-v2-test.byte-trade.com',
},
'logo': 'https://user-images.githubusercontent.com/1294454/67288762-2f04a600-f4e6-11e9-9fd6-c60641919491.jpg',
'api': 'https://api-v2.byte-trade.com',
'api': {
'market': 'https://api-v2.bytetrade.com',
'public': 'https://api-v2.bytetrade.com',
},
'www': 'https://www.byte-trade.com',
'doc': 'https://github.com/Bytetrade/bytetrade-official-api-docs/wiki',
},
@@ -1222,7 +1228,7 @@ module.exports = class bytetrade extends Exchange {
this.numberToLE (address.length, 1),
this.stringToBinary (this.encode (address)),
this.numberToLE (parseInt (coinId), 4),
this.numberToLE (Math.floor (parseInt (parseFloat (this.integerDivide (amountChain, eightBytes)))), 8),
this.numberToLE (this.integerDivide (amountChain, eightBytes), 8),
this.numberToLE (this.integerModulo (amountChain, eightBytes), 8),
this.numberToLE (1, 1),
this.numberToLE (this.integerDivide (assetFee, eightBytes), 8),
@@ -1255,7 +1261,7 @@ module.exports = class bytetrade extends Exchange {
this.numberToLE (middleAddress.length, 1),
this.stringToBinary (this.encode (middleAddress)),
this.numberToLE (parseInt (coinId), 4),
this.numberToLE (Math.floor (parseInt (parseFloat (this.integerDivide (amountChain, eightBytes)))), 8),
this.numberToLE (this.integerDivide (amountChain, eightBytes), 8),
this.numberToLE (this.integerModulo (amountChain, eightBytes), 8),
this.numberToLE (0, 1),
this.numberToLE (1, 1),
@@ -1358,7 +1364,7 @@ module.exports = class bytetrade extends Exchange {
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
let url = this.urls['api'];
let url = this.urls['api'][api];
url += '/' + path;
if (Object.keys (params).length) {
url += '?' + this.urlencode (params);
+37 -1
View File
@@ -564,9 +564,45 @@ module.exports = class cex extends Exchange {
request['order_type'] = type;
}
const response = await this.privatePostPlaceOrderPair (this.extend (request, params));
//
// {
// "id": "12978363524",
// "time": 1586610022259,
// "type": "buy",
// "price": "0.033934",
// "amount": "0.10722802",
// "pending": "0.10722802",
// "complete": false
// }
//
const placedAmount = this.safeFloat (response, 'amount');
const remaining = this.safeFloat (response, 'pending');
const timestamp = this.safeValue (response, 'time');
const complete = this.safeValue (response, 'complete');
const status = complete ? 'closed' : 'open';
let filled = undefined;
if ((placedAmount !== undefined) && (remaining !== undefined)) {
filled = Math.max (placedAmount - remaining, 0);
}
return {
'id': this.safeString (response, 'id'),
'info': response,
'id': response['id'],
'clientOrderId': undefined,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'type': type,
'side': this.safeString (response, 'type'),
'symbol': symbol,
'status': status,
'price': this.safeFloat (response, 'price'),
'amount': placedAmount,
'cost': undefined,
'average': undefined,
'remaining': remaining,
'filled': filled,
'fee': undefined,
'trades': undefined,
};
}
+6 -2
View File
@@ -561,6 +561,7 @@ module.exports = class coinmate extends Exchange {
const statuses = {
'FILLED': 'closed',
'CANCELLED': 'canceled',
'PARTIALLY_FILLED': 'open',
'OPEN': 'open',
};
return this.safeString (statuses, status, status);
@@ -623,12 +624,15 @@ module.exports = class coinmate extends Exchange {
const price = this.safeFloat (order, 'price');
const amount = this.safeFloat2 (order, 'originalAmount', 'amount');
const remaining = this.safeFloat (order, 'remainingAmount', amount);
const status = this.parseOrderStatus (this.safeString (order, 'status'));
let status = this.parseOrderStatus (this.safeString (order, 'status'));
const type = this.parseOrderType (this.safeString (order, 'orderTradeType'));
let filled = undefined;
let cost = undefined;
if ((amount !== undefined) && (remaining !== undefined)) {
filled = amount - remaining;
filled = Math.min (amount - remaining, 0);
if (remaining === 0) {
status = 'closed';
}
if (price !== undefined) {
cost = filled * price;
}
-1
View File
@@ -129,7 +129,6 @@ module.exports = class crex24 extends Exchange {
'fetchClosedOrdersMethod': 'tradingGetOrderHistory', // or 'tradingGetActiveOrders'
'fetchTickersMethod': 'publicGetTicker24hr',
'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
'defaultLimitOrderType': 'limit', // or 'limit_maker'
'hasAlreadyAuthenticatedSuccessfully': false,
'warnOnFetchOpenOrdersWithoutSymbol': true,
'parseOrderToPrecision': false, // force amounts and costs in parseOrder to precision
+4 -2
View File
@@ -525,11 +525,13 @@ module.exports = class deribit extends Exchange {
'info': response,
};
const balance = this.safeValue (response, 'result', {});
const currencyId = this.safeString (balance, 'currency');
const currencyCode = this.safeCurrencyCode (currencyId);
const account = this.account ();
account['free'] = this.safeFloat (balance, 'availableFunds');
account['used'] = this.safeFloat (balance, 'maintenanceMargin');
account['total'] = this.safeFloat (balance, 'equity');
result[code] = account;
result[currencyCode] = account;
return this.parseBalance (result);
}
@@ -883,7 +885,7 @@ module.exports = class deribit extends Exchange {
// M = maker, T = taker, MT = both
takerOrMaker = (liquidity === 'M') ? 'maker' : 'taker';
}
const feeCost = this.safeFloat (trade, 'feeCost');
const feeCost = this.safeFloat (trade, 'fee');
let fee = undefined;
if (feeCost !== undefined) {
const feeCurrencyId = this.safeString (trade, 'fee_currency');
+363 -152
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ArgumentsRequired, ExchangeError, OrderNotFound, AuthenticationError, InsufficientFunds, InvalidOrder, InvalidNonce, NotSupported, OnMaintenance, RateLimitExceeded } = require ('./base/errors');
const { ArgumentsRequired, ExchangeError, OrderNotFound, AuthenticationError, InsufficientFunds, InvalidOrder, InvalidNonce, NotSupported, OnMaintenance, RateLimitExceeded, BadRequest, PermissionDenied } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -14,7 +14,7 @@ module.exports = class exmo extends Exchange {
'name': 'EXMO',
'countries': [ 'ES', 'RU' ], // Spain, Russia
'rateLimit': 350, // once every 350 ms ≈ 180 requests per minute ≈ 3 requests per second
'version': 'v1',
'version': 'v1.1',
'has': {
'CORS': false,
'fetchClosedOrders': 'emulated',
@@ -32,6 +32,21 @@ module.exports = class exmo extends Exchange {
'fetchFundingFees': true,
'fetchCurrencies': true,
'fetchTransactions': true,
'fetchOHLCV': true,
},
'timeframes': {
'1m': '1',
'5m': '5',
'15m': '15',
'30m': '30',
'45m': '45',
'1h': '60',
'2h': '120',
'3h': '180',
'4h': '240',
'1d': 'D',
'1w': 'W',
'1M': 'M',
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27766491-1b0ea956-5eda-11e7-9225-40d67b481b8d.jpg',
@@ -62,6 +77,7 @@ module.exports = class exmo extends Exchange {
'pair_settings',
'ticker',
'trades',
'candles_history',
],
},
'private': {
@@ -69,6 +85,8 @@ module.exports = class exmo extends Exchange {
'user_info',
'order_create',
'order_cancel',
'stop_market_order_create',
'stop_market_order_cancel',
'user_open_orders',
'user_trades',
'user_cancelled_orders',
@@ -103,86 +121,90 @@ module.exports = class exmo extends Exchange {
'error': '',
'data': {
'limits': [
{ 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
{ 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' },
{ 'pair': 'ALGO/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
{ 'pair': 'ALGO/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '50' },
{ 'pair': 'ATOM/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '50000000' },
{ 'pair': 'ATOM/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' },
{ 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' },
{ 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
{ 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' },
{ 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' },
{ 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' },
{ 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
{ 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' },
{ 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' },
{ 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' },
{ 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
{ 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
{ 'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000' },
{ 'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000' },
{ 'pair': 'BTC/GBP', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'ETH/GBP', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'XRP/GBP', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
{ 'pair': 'USDT/GBP', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000' },
{ 'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000' },
{ 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' },
{ 'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
{ 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
{ 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '100000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' },
{ 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
{ 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' },
{ 'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' },
{ 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' },
{ 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' },
{ 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' },
{ 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '10000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' },
{ 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'ALGO/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'ALGO/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
{ 'pair': 'ALGO/EUR', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'ATOM/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'ATOM/EUR', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' },
{ 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' },
{ 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' },
{ 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' },
{ 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' },
{ 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' },
{ 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' },
{ 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' },
{ 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' },
{ 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' },
{ 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' },
{ 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
{ 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
{ 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000' },
{ 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000' },
{ 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
{ 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' },
{ 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
{ 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' },
{ 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000' },
{ 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000' },
{ 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '1000000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' },
{ 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' },
{ 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000' },
{ 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000' },
{ 'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000' },
{ 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000' },
{ 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' },
{ 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' },
{ 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' },
{ 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' },
{ 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
{ 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' },
{ 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
{ 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
@@ -197,84 +219,94 @@ module.exports = class exmo extends Exchange {
{ 'pair': 'KICK/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
{ 'pair': 'KICK/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'KICK/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' },
{ 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' },
{ 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' },
{ 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
{ 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' },
{ 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' },
{ 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' },
{ 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
{ 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' },
{ 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100' },
{ 'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000' },
{ 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' },
{ 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' },
{ 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' },
{ 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' },
{ 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' },
{ 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' },
{ 'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'MNX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
{ 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' },
{ 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
{ 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' },
{ 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' },
{ 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' },
{ 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' },
{ 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' },
{ 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' },
{ 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
{ 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' },
{ 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
{ 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' },
{ 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' },
{ 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' },
{ 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
{ 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' },
{ 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' },
{ 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' },
{ 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' },
{ 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' },
{ 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' },
{ 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' },
{ 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' },
{ 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
{ 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
{ 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' },
{ 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
{ 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'TRX/EUR', 'min_q': '0.01', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
{ 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
{ 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000' },
{ 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
{ 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' },
{ 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' },
{ 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' },
{ 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
{ 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
{ 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' },
{ 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' },
{ 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' },
{ 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
{ 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' },
{ 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '200000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' },
{ 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '200000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' },
{ 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' },
{ 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
{ 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' },
{ 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' },
{ 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
{ 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' },
{ 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
{ 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
{ 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' },
{ 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' },
{ 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' },
{ 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
{ 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
{ 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' },
{ 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' },
{ 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' },
{ 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' },
{ 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
{ 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' },
{ 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' },
{ 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
{ 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' },
{ 'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000' },
{ 'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000' },
{ 'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
{ 'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000' },
{ 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
{ 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '1000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
{ 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
{ 'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
{ 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
@@ -337,6 +369,8 @@ module.exports = class exmo extends Exchange {
{ 'prov': 'CRON', 'dep': '0%', 'wd': '5 CRON' },
{ 'prov': 'ONT', 'dep': '0%', 'wd': '1 ONT' },
{ 'prov': 'ONG', 'dep': '0%', 'wd': '5 ONG' },
{ 'prov': 'ALGO', 'dep': '0%', 'wd': '0.01 ALGO' },
{ 'prov': 'ATOM', 'dep': '0%', 'wd': '' },
],
},
{
@@ -345,9 +379,10 @@ module.exports = class exmo extends Exchange {
'items': [
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' },
{ 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.99%' },
{ 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' },
{ 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 USD', 'wd': '-' },
{ 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' },
{ 'prov': 'Frick Bank', 'dep': '0 USD', 'wd': '-' },
],
},
{
@@ -355,22 +390,24 @@ module.exports = class exmo extends Exchange {
'title': 'EUR',
'items': [
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 EUR', 'wd': '-' },
{ 'prov': 'Visa/MasterCard', 'dep': '4.5% + 0.5 EUR', 'wd': '-' },
{ 'prov': 'Visa', 'dep': '2.95%', 'wd': '-' },
{ 'prov': 'SEPA', 'dep': '10 EUR', 'wd': '50 EUR' },
{ 'prov': 'Frick Internal Transfer', 'dep': '0 EUR', 'wd': '-' },
{ 'prov': 'SEPA Frick Bank', 'dep': '0 EUR', 'wd': '-' },
{ 'prov': 'WIRE Frick Bank', 'dep': '0%', 'wd': '-' },
{ 'prov': 'SEPA Weg Ag', 'dep': '-', 'wd': '1 EUR' },
],
},
{
'group': 'rub',
'title': 'RUB',
'items': [
{ 'prov': 'Payeer', 'dep': '2.49%', 'wd': '-' },
{ 'prov': 'Payeer', 'dep': '2.49%', 'wd': '3.99%' },
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Qiwi', 'dep': '0.99%', 'wd': '2%' },
{ 'prov': 'Yandex Money', 'dep': '1.95%', 'wd': '-' },
{ 'prov': 'Enfins', 'dep': '0%', 'wd': '1.49%' },
{ 'prov': 'AdvCash', 'dep': '0%', 'wd': '2.49%' },
{ 'prov': 'Visa/MasterCard', 'dep': '1.99%', 'wd': '4.49% + 60 RUB' },
{ 'prov': 'Qiwi', 'dep': '1.49%', 'wd': '2.49%' },
{ 'prov': 'Yandex Money', 'dep': '1.49%', 'wd': '-' },
{ 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' },
{ 'prov': 'Visa/MasterCard', 'dep': '2.99%', 'wd': '3.99% + 60 RUB' },
],
},
{
@@ -378,7 +415,6 @@ module.exports = class exmo extends Exchange {
'title': 'PLN',
'items': [
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 1 PLN', 'wd': '-' },
],
},
{
@@ -388,6 +424,7 @@ module.exports = class exmo extends Exchange {
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Visa', 'dep': '3.05%', 'wd': '-' },
{ 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 2 TRY', 'wd': '-' },
{ 'prov': 'AdvCash', 'dep': '0%', 'wd': '-' },
],
},
{
@@ -396,17 +433,18 @@ module.exports = class exmo extends Exchange {
'items': [
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Terminal', 'dep': '2.6%', 'wd': '-' },
{ 'prov': 'Enfins', 'dep': '0%', 'wd': '1.95%' },
{ 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '2.99%' },
{ 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '-' },
{ 'prov': 'Visa/MasterCard EasyTransfer', 'dep': '-', 'wd': '2.99%' },
],
},
{
'group': 'kzt',
'title': 'KZT',
'items': [
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Visa/MasterCard RoyalPay', 'dep': '-', 'wd': '2.99% + 450 KZT' },
{ 'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '-' },
{ 'prov': 'AdvCash', 'dep': '0%', 'wd': '1.49%' },
{ 'prov': 'AdvCash', 'dep': '0%', 'wd': '-' },
],
},
],
@@ -420,6 +458,7 @@ module.exports = class exmo extends Exchange {
'40015': ExchangeError, // API function do not exist
'40016': OnMaintenance, // {"result":false,"error":"Error 40016: Maintenance work in progress"}
'40017': AuthenticationError, // Wrong API Key
'40032': PermissionDenied, // {"result":false,"error":"Error 40032: Access is denied for this API key"}
'40034': RateLimitExceeded, // {"result":false,"error":"Error 40034: Access is denied, rate limit is exceeded"}
'50052': InsufficientFunds,
'50054': InsufficientFunds,
@@ -429,6 +468,8 @@ module.exports = class exmo extends Exchange {
'50321': InvalidOrder, // Price by order is more than permissible maximum for this pair
},
'broad': {
'range period is too long': BadRequest,
'invalid syntax': BadRequest,
'API rate limit exceeded': RateLimitExceeded, // {"result":false,"error":"API rate limit exceeded for 99.33.55.224. Retry after 60 sec.","history":[],"begin":1579392000,"end":1579478400}
},
},
@@ -590,8 +631,21 @@ module.exports = class exmo extends Exchange {
}
async fetchMarkets (params = {}) {
const fees = await this.fetchTradingFees ();
const response = await this.publicGetPairSettings (params);
//
// {
// "EXM_ETH": {
// "min_quantity": "1",
// "max_quantity": "1000",
// "min_price": "1",
// "max_price": "1000",
// "max_amount": "1000",
// "min_amount": "1",
// "commission_taker_percent": "0.2",
// "commission_maker_percent": "0.2"
// },
// }
//
const keys = Object.keys (response);
const result = [];
for (let i = 0; i < keys.length; i++) {
@@ -601,6 +655,8 @@ module.exports = class exmo extends Exchange {
const [ baseId, quoteId ] = symbol.split ('/');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const taker = this.safeFloat (market, 'commission_taker_percent');
const maker = this.safeFloat (market, 'commission_maker_percent');
result.push ({
'id': id,
'symbol': symbol,
@@ -609,8 +665,8 @@ module.exports = class exmo extends Exchange {
'baseId': baseId,
'quoteId': quoteId,
'active': true,
'taker': fees['taker'],
'maker': fees['maker'],
'taker': taker / 100,
'maker': maker / 100,
'limits': {
'amount': {
'min': this.safeFloat (market, 'min_quantity'),
@@ -635,6 +691,74 @@ module.exports = class exmo extends Exchange {
return result;
}
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
'resolution': this.timeframes[timeframe],
};
const options = this.safeValue (this.options, 'fetchOHLCV');
const maxLimit = this.safeInteger (options, 'maxLimit', 3000);
const duration = this.parseTimeframe (timeframe);
const now = this.milliseconds ();
if (since === undefined) {
if (limit === undefined) {
throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument');
} else {
if (limit > maxLimit) {
throw new BadRequest (this.id + ' fetchOHLCV will serve ' + maxLimit.toString () + ' candles at most');
}
request['from'] = parseInt (now / 1000) - limit * duration - 1;
request['to'] = parseInt (now / 1000);
}
} else {
request['from'] = parseInt (since / 1000) - 1;
if (limit === undefined) {
request['to'] = parseInt (now / 1000);
} else {
if (limit > maxLimit) {
throw new BadRequest (this.id + ' fetchOHLCV will serve ' + maxLimit.toString () + ' candles at most');
}
const to = this.sum (since, limit * duration * 1000);
request['to'] = parseInt (to / 1000);
}
}
const response = await this.publicGetCandlesHistory (this.extend (request, params));
//
// {
// "candles":[
// {"t":1584057600000,"o":0.02235144,"c":0.02400233,"h":0.025171,"l":0.02221,"v":5988.34031761},
// {"t":1584144000000,"o":0.0240373,"c":0.02367413,"h":0.024399,"l":0.0235,"v":2027.82522329},
// {"t":1584230400000,"o":0.02363458,"c":0.02319242,"h":0.0237948,"l":0.02223196,"v":1707.96944997},
// ]
// }
//
const candles = this.safeValue (response, 'candles', []);
return this.parseOHLCVs (candles, market, timeframe, since, limit);
}
parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
//
// {
// "t":1584057600000,
// "o":0.02235144,
// "c":0.02400233,
// "h":0.025171,
// "l":0.02221,
// "v":5988.34031761
// }
//
return [
this.safeInteger (ohlcv, 't'),
this.safeFloat (ohlcv, 'o'),
this.safeFloat (ohlcv, 'h'),
this.safeFloat (ohlcv, 'l'),
this.safeFloat (ohlcv, 'c'),
this.safeFloat (ohlcv, 'v'),
];
}
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.privatePostUserInfo (params);
@@ -758,8 +882,36 @@ module.exports = class exmo extends Exchange {
}
parseTrade (trade, market = undefined) {
//
// fetchTrades (public)
//
// {
// "trade_id":165087520,
// "date":1587470005,
// "type":"buy",
// "quantity":"1.004",
// "price":"0.02491461",
// "amount":"0.02501426"
// },
//
// fetchMyTrades, fetchOrderTrades
//
// {
// "trade_id": 3,
// "date": 1435488248,
// "type": "buy",
// "pair": "BTC_USD",
// "order_id": 12345,
// "quantity": 1,
// "price": 100,
// "amount": 100,
// "exec_type": "taker",
// "commission_amount": "0.02",
// "commission_currency": "BTC",
// "commission_percent": "0.2"
// }
//
const timestamp = this.safeTimestamp (trade, 'date');
let fee = undefined;
let symbol = undefined;
const id = this.safeString (trade, 'trade_id');
const orderId = this.safeString (trade, 'order_id');
@@ -768,24 +920,35 @@ module.exports = class exmo extends Exchange {
const cost = this.safeFloat (trade, 'amount');
const side = this.safeString (trade, 'type');
const type = undefined;
if (market !== undefined) {
const marketId = this.safeString (trade, 'pair');
if (marketId !== undefined) {
if (marketId in this.markets_by_id) {
market = this.markets_by_id[marketId];
} else {
const [ baseId, quoteId ] = marketId.split ('_');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
symbol = base + '/' + quote;
}
}
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
if (market['taker'] !== market['maker']) {
throw new ExchangeError (this.id + ' parseTrade can not deduce proper fee costs, taker and maker fees now differ');
}
if ((side === 'buy') && (amount !== undefined)) {
fee = {
'currency': market['base'],
'cost': amount * market['taker'],
'rate': market['taker'],
};
} else if ((side === 'sell') && (cost !== undefined)) {
fee = {
'currency': market['quote'],
'cost': cost * market['taker'],
'rate': market['taker'],
};
}
const takerOrMaker = this.safeString (trade, 'exec_type');
let fee = undefined;
const feeCost = this.safeFloat (trade, 'commission_amount');
if (feeCost !== undefined) {
const feeCurrencyId = this.safeString (trade, 'commission_currency');
const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
let feeRate = this.safeFloat (trade, 'commission_percent');
if (feeRate !== undefined) {
feeRate /= 1000;
}
fee = {
'cost': feeCost,
'currency': feeCurrencyCode,
'rate': feeRate,
};
}
return {
'id': id,
@@ -796,7 +959,7 @@ module.exports = class exmo extends Exchange {
'order': orderId,
'type': type,
'side': side,
'takerOrMaker': undefined,
'takerOrMaker': takerOrMaker,
'price': price,
'amount': amount,
'cost': cost,
@@ -811,6 +974,28 @@ module.exports = class exmo extends Exchange {
'pair': market['id'],
};
const response = await this.publicGetTrades (this.extend (request, params));
//
// {
// "ETH_BTC":[
// {
// "trade_id":165087520,
// "date":1587470005,
// "type":"buy",
// "quantity":"1.004",
// "price":"0.02491461",
// "amount":"0.02501426"
// },
// {
// "trade_id":165087369,
// "date":1587469938,
// "type":"buy",
// "quantity":"0.94",
// "price":"0.02492348",
// "amount":"0.02342807"
// }
// ]
// }
//
const data = this.safeValue (response, market['id'], []);
return this.parseTrades (data, market, since, limit);
}
@@ -968,6 +1153,31 @@ module.exports = class exmo extends Exchange {
'order_id': id.toString (),
};
const response = await this.privatePostOrderTrades (this.extend (request, params));
//
// {
// "type": "buy",
// "in_currency": "BTC",
// "in_amount": "1",
// "out_currency": "USD",
// "out_amount": "100",
// "trades": [
// {
// "trade_id": 3,
// "date": 1435488248,
// "type": "buy",
// "pair": "BTC_USD",
// "order_id": 12345,
// "quantity": 1,
// "price": 100,
// "amount": 100,
// "exec_type": "taker",
// "commission_amount": "0.02",
// "commission_currency": "BTC",
// "commission_percent": "0.2"
// }
// ]
// }
//
const trades = this.safeValue (response, 'trades');
return this.parseTrades (trades, market, since, limit);
}
@@ -1415,9 +1625,10 @@ module.exports = class exmo extends Exchange {
if (response === undefined) {
return; // fallback to default error handler
}
if ('result' in response) {
if (('result' in response) || ('errmsg' in response)) {
//
// {"result":false,"error":"Error 50052: Insufficient funds"}
// {"s":"error","errmsg":"strconv.ParseInt: parsing \"\": invalid syntax"}
//
let success = this.safeValue (response, 'result', false);
if (typeof success === 'string') {
@@ -1429,7 +1640,7 @@ module.exports = class exmo extends Exchange {
}
if (!success) {
let code = undefined;
const message = this.safeString (response, 'error');
const message = this.safeString2 (response, 'error', 'errmsg');
const errorParts = message.split (':');
const numParts = errorParts.length;
if (numParts > 1) {
+4
View File
@@ -580,6 +580,7 @@ module.exports = class ftx extends Exchange {
// {
// "fee": 20.1374935,
// "feeRate": 0.0005,
// "feeCurrency": "USD",
// "future": "EOS-0329",
// "id": 11215,
// "liquidity": "taker",
@@ -626,8 +627,11 @@ module.exports = class ftx extends Exchange {
let fee = undefined;
const feeCost = this.safeFloat (trade, 'fee');
if (feeCost !== undefined) {
const feeCurrencyId = this.safeString (trade, 'feeCurrency');
const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
fee = {
'cost': feeCost,
'currency': feeCurrencyCode,
'rate': this.safeFloat (trade, 'feeRate'),
};
}
+94 -25
View File
@@ -164,6 +164,26 @@ module.exports = class gateio extends Exchange {
async fetchMarkets (params = {}) {
const response = await this.publicGetMarketinfo (params);
//
// {
// "result":"true",
// "pairs":[
// {
// "usdt_cnyx":{
// "decimal_places":3,
// "amount_decimal_places":3,
// "min_amount":1,
// "min_amount_a":1,
// "min_amount_b":3,
// "fee":0.02,
// "trade_disabled":0,
// "buy_disabled":0,
// "sell_disabled":0
// }
// },
// ]
// }
//
const markets = this.safeValue (response, 'pairs');
if (!markets) {
throw new ExchangeError (this.id + ' fetchMarkets got an unrecognized response');
@@ -190,14 +210,14 @@ module.exports = class gateio extends Exchange {
const symbol = base + '/' + quote;
const precision = {
'amount': 8,
'price': details['decimal_places'],
'price': this.safeInteger (details, 'decimal_places'),
};
const amountLimits = {
'min': details['min_amount'],
'min': this.safeFloat (details, 'min_amount'),
'max': undefined,
};
const priceLimits = {
'min': Math.pow (10, -details['decimal_places']),
'min': Math.pow (10, -precision['price']),
'max': undefined,
};
const defaultCost = amountLimits['min'] * priceLimits['min'];
@@ -211,9 +231,13 @@ module.exports = class gateio extends Exchange {
'price': priceLimits,
'cost': costLimits,
};
const active = true;
const disabled = this.safeValue (details, 'trade_disabled');
const active = !disabled;
const uppercaseId = id.toUpperCase ();
const fee = this.safeFloat (details, 'fee');
result.push ({
'id': id,
'uppercaseId': uppercaseId,
'symbol': symbol,
'base': base,
'quote': quote,
@@ -221,8 +245,8 @@ module.exports = class gateio extends Exchange {
'quoteId': quoteId,
'info': market,
'active': active,
'maker': details['fee'] / 100,
'taker': details['fee'] / 100,
'maker': fee / 100,
'taker': fee / 100,
'precision': precision,
'limits': limits,
});
@@ -484,22 +508,64 @@ module.exports = class gateio extends Exchange {
parseOrder (order, market = undefined) {
//
// {'amount': '0.00000000',
// 'currencyPair': 'xlm_usdt',
// 'fee': '0.0113766632239302 USDT',
// 'feeCurrency': 'USDT',
// 'feePercentage': 0.18,
// 'feeValue': '0.0113766632239302',
// 'filledAmount': '30.14004987',
// 'filledRate': 0.2097,
// 'initialAmount': '30.14004987',
// 'initialRate': '0.2097',
// 'left': 0,
// 'orderNumber': '998307286',
// 'rate': '0.2097',
// 'status': 'closed',
// 'timestamp': 1531158583,
// 'type': 'sell'},
// createOrder
//
// {
// "fee": "0 ZEC",
// "code": 0,
// "rate": "0.0055",
// "side": 2,
// "type": "buy",
// "ctime": 1586460839.138,
// "market": "ZEC_BTC",
// "result": "true",
// "status": "open",
// "iceberg": "0",
// "message": "Success",
// "feeValue": "0",
// "filledRate": "0.005500000",
// "leftAmount": "0.60607456",
// "feeCurrency": "ZEC",
// "orderNumber": 10755887009,
// "filledAmount": "0",
// "feePercentage": 0.002,
// "initialAmount": "0.60607456"
// }
//
// {
// 'amount': '0.00000000',
// 'currencyPair': 'xlm_usdt',
// 'fee': '0.0113766632239302 USDT',
// 'feeCurrency': 'USDT',
// 'feePercentage': 0.18,
// 'feeValue': '0.0113766632239302',
// 'filledAmount': '30.14004987',
// 'filledRate': 0.2097,
// 'initialAmount': '30.14004987',
// 'initialRate': '0.2097',
// 'left': 0,
// 'orderNumber': '998307286',
// 'rate': '0.2097',
// 'status': 'closed',
// 'timestamp': 1531158583,
// 'type': 'sell'
// }
//
// {
// "orderNumber": 10802237760,
// "orderType": 1,
// "type": "buy",
// "rate": "0.54250000",
// "amount": "45.55638518",
// "total": "24.71433896",
// "initialRate": "0.54250000",
// "initialAmount": "45.55638518",
// "filledRate": "0.54250000",
// "filledAmount": "0",
// "currencyPair": "nano_usdt",
// "timestamp": 1586556143,
// "status": "open"
// }
//
const id = this.safeString2 (order, 'orderNumber', 'id');
let symbol = undefined;
@@ -520,12 +586,15 @@ module.exports = class gateio extends Exchange {
} else if (side === '2') {
side = 'buy';
}
const price = this.safeFloat2 (order, 'initialRate', 'price');
const price = this.safeFloat2 (order, 'initialRate', 'rate');
const average = this.safeFloat (order, 'filledRate');
const amount = this.safeFloat2 (order, 'initialAmount', 'amount');
const filled = this.safeFloat (order, 'filledAmount');
// In the order status response, this field has a different name.
const remaining = this.safeFloat2 (order, 'leftAmount', 'left');
let remaining = this.safeFloat2 (order, 'leftAmount', 'left');
if (remaining === undefined) {
remaining = amount - filled;
}
const feeCost = this.safeFloat (order, 'feeValue');
const feeCurrencyId = this.safeString (order, 'feeCurrency');
const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
@@ -651,7 +720,7 @@ module.exports = class gateio extends Exchange {
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' fetchMyTrades requires symbol param');
throw new ArgumentsRequired (this.id + ' fetchMyTrades requires symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
+60 -54
View File
@@ -180,8 +180,7 @@ module.exports = class gemini extends Exchange {
if (numTables < 2) {
throw new NotSupported (error);
}
// tables[1] = tables[1].replace ("\n", ''); // eslint-disable-line quotes
const rows = tables[1].split ("<tr>\n"); // eslint-disable-line quotes
const rows = tables[1].split ("\n<tr>\n"); // eslint-disable-line quotes
const numRows = rows.length;
if (numRows < 2) {
throw new NotSupported (error);
@@ -192,66 +191,73 @@ module.exports = class gemini extends Exchange {
const row = rows[i];
const cells = row.split ("</td>\n"); // eslint-disable-line quotes
const numCells = cells.length;
if (numCells < 7) {
if (numCells < 9) {
throw new NotSupported (error);
}
//
// [
// '<td><code class="prettyprint">btcusd</code>',
// '<td>USD', // quote
// '<td>BTC', // base
// '<td>0.00001 BTC (1e-5)', // min amount
// '<td>0.00000001 BTC (1e-8)', // amount min tick size
// '<td>0.01 USD', // price min tick size
// '</tr>\n'
// '<td>BTC', // currency
// '<td>0.00001 BTC (1e-5)', // min order size
// '<td>0.00000001 BTC (1e-8)', // tick size
// '<td>0.01 USD', // usd price increment
// '<td>N/A', // btc price increment
// '<td>0.0001 ETH (1e-4)', // eth price increment
// '<td>0.0001 BCH (1e-4)', // bch price increment
// '<td>0.001 LTC (1e-3)', // ltc price increment
// '</tr>'
// ]
//
let id = cells[0].replace ('<td>', '');
id = id.replace ('<code class="prettyprint">', '');
id = id.replace ('</code>', '');
let baseId = cells[2].replace ('<td>', '');
let quoteId = cells[1].replace ('<td>', '');
const minAmountAsString = cells[3].replace ('<td>', '');
const amountTickSizeAsString = cells[4].replace ('<td>', '');
const priceTickSizeAsString = cells[5].replace ('<td>', '');
const minAmount = minAmountAsString.split (' ');
const amountPrecision = amountTickSizeAsString.split (' ');
const pricePrecision = priceTickSizeAsString.split (' ');
baseId = baseId.toLowerCase ();
quoteId = quoteId.toLowerCase ();
const uppercaseBaseId = cells[0].replace ('<td>', '');
const baseId = uppercaseBaseId.toLowerCase ();
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const precision = {
'amount': this.precisionFromString (amountPrecision[0]),
'price': this.precisionFromString (pricePrecision[0]),
};
const active = undefined;
result.push ({
'id': id,
'info': row,
'symbol': symbol,
'base': base,
'quote': quote,
'baseId': baseId,
'quoteId': quoteId,
'active': active,
'precision': precision,
'limits': {
'amount': {
'min': parseFloat (minAmount[0]),
'max': undefined,
const quoteIds = [ 'usd', 'btc', 'eth', 'bch', 'ltc' ];
const minAmountString = cells[1].replace ('<td>', '');
const minAmountParts = minAmountString.split (' ');
const minAmount = this.safeFloat (minAmountParts, 0);
const amountPrecisionString = cells[2].replace ('<td>', '');
const amountPrecisionParts = amountPrecisionString.split (' ');
const amountPrecision = this.precisionFromString (amountPrecisionParts[0]);
for (let j = 0; j < quoteIds.length; j++) {
const quoteId = quoteIds[j];
const quote = this.safeCurrencyCode (quoteId);
const pricePrecisionIndex = this.sum (3, j);
const pricePrecisionString = cells[pricePrecisionIndex].replace ('<td>', '');
if (pricePrecisionString === 'N/A') {
continue;
}
const pricePrecisionParts = pricePrecisionString.split (' ');
const pricePrecision = this.precisionFromString (pricePrecisionParts[0]);
const symbol = base + '/' + quote;
const id = baseId + quoteId;
const active = undefined;
result.push ({
'id': id,
'info': row,
'symbol': symbol,
'base': base,
'quote': quote,
'baseId': baseId,
'quoteId': quoteId,
'active': active,
'precision': {
'amount': amountPrecision,
'price': pricePrecision,
},
'price': {
'min': undefined,
'max': undefined,
'limits': {
'amount': {
'min': minAmount,
'max': undefined,
},
'price': {
'min': undefined,
'max': undefined,
},
'cost': {
'min': undefined,
'max': undefined,
},
},
'cost': {
'min': undefined,
'max': undefined,
},
},
});
});
}
}
return result;
}
+2019
View File
File diff suppressed because it is too large. Load diff
+6 -7
View File
@@ -730,14 +730,13 @@ module.exports = class hitbtc extends Exchange {
}
parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
const timestamp = this.parse8601 (ohlcv['timestamp']);
return [
timestamp,
parseFloat (ohlcv['open']),
parseFloat (ohlcv['max']),
parseFloat (ohlcv['min']),
parseFloat (ohlcv['close']),
parseFloat (ohlcv['volume']),
this.parse8601 (this.safeString (ohlcv, 'timestamp')),
this.safeFloat (ohlcv, 'open'),
this.safeFloat (ohlcv, 'max'),
this.safeFloat (ohlcv, 'min'),
this.safeFloat (ohlcv, 'close'),
this.safeFloat (ohlcv, 'volume'),
];
}
-17
View File
@@ -1,17 +0,0 @@
'use strict';
// ---------------------------------------------------------------------------
const hitbtc = require ('./hitbtc');
// ---------------------------------------------------------------------------
module.exports = class hitbtc2 extends hitbtc {
describe () {
// this is a temporary stub for backward compatibility
// https://github.com/ccxt/ccxt/issues/6678
return this.deepExtend (super.describe (), {
'id': 'hitbtc2',
});
}
};
+27 -1
View File
@@ -163,12 +163,14 @@ module.exports = class huobipro extends Exchange {
'exceptions': {
'exact': {
// err-code
'bad-request': BadRequest,
'api-not-support-temp-addr': PermissionDenied, // {"status":"error","err-code":"api-not-support-temp-addr","err-msg":"API withdrawal does not support temporary addresses","data":null}
'timeout': RequestTimeout, // {"ts":1571653730865,"status":"error","err-code":"timeout","err-msg":"Request Timeout"}
'gateway-internal-error': ExchangeNotAvailable, // {"status":"error","err-code":"gateway-internal-error","err-msg":"Failed to load data. Try again later.","data":null}
'account-frozen-balance-insufficient-error': InsufficientFunds, // {"status":"error","err-code":"account-frozen-balance-insufficient-error","err-msg":"trade account balance is not enough, left: `0.0027`","data":null}
'invalid-amount': InvalidOrder, // eg "Paramemter `amount` is invalid."
'order-limitorder-amount-min-error': InvalidOrder, // limit order amount error, min: `0.001`
'order-limitorder-amount-max-error': InvalidOrder, // market order amount error, max: `1000000`
'order-marketorder-amount-min-error': InvalidOrder, // market order amount error, min: `0.01`
'order-limitorder-price-min-error': InvalidOrder, // limit order price error
'order-limitorder-price-max-error': InvalidOrder, // limit order price error
@@ -331,6 +333,8 @@ module.exports = class huobipro extends Exchange {
}
parseTicker (ticker, market = undefined) {
//
// fetchTicker
//
// {
// "amount": 26228.672978342216,
@@ -346,25 +350,47 @@ module.exports = class huobipro extends Exchange {
// "bid": [ 9146.86, 0.080758 ],
// }
//
// fetchTickers
// {
// symbol: "bhdht",
// open: 2.3938,
// high: 2.4151,
// low: 2.3323,
// close: 2.3909,
// amount: 628.992,
// vol: 1493.71841095,
// count: 2088,
// bid: 2.3643,
// bidSize: 0.7136,
// ask: 2.4061,
// askSize: 0.4156
// }
//
let symbol = undefined;
if (market !== undefined) {
symbol = market['symbol'];
}
const timestamp = this.safeInteger (ticker, 'ts');
let bid = undefined;
let ask = undefined;
let bidVolume = undefined;
let ask = undefined;
let askVolume = undefined;
if ('bid' in ticker) {
if (Array.isArray (ticker['bid'])) {
bid = this.safeFloat (ticker['bid'], 0);
bidVolume = this.safeFloat (ticker['bid'], 1);
} else {
bid = this.safeFloat (ticker, 'bid');
bidVolume = this.safeValue (ticker, 'bidSize');
}
}
if ('ask' in ticker) {
if (Array.isArray (ticker['ask'])) {
ask = this.safeFloat (ticker['ask'], 0);
askVolume = this.safeFloat (ticker['ask'], 1);
} else {
ask = this.safeFloat (ticker, 'ask');
askVolume = this.safeValue (ticker, 'askSize');
}
}
const open = this.safeFloat (ticker, 'open');
+2 -2
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, AuthenticationError } = require ('./base/errors');
const { ExchangeError, AuthenticationError, ArgumentsRequired } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -221,7 +221,7 @@ module.exports = class ice3x extends Exchange {
const type = this.safeString (params, 'type');
if ((type !== 'ask') && (type !== 'bid')) {
// eslint-disable-next-line quotes
throw new ExchangeError (this.id + " fetchOrderBook requires an exchange-specific extra 'type' param ('bid' or 'ask') when used with a limit");
throw new ArgumentsRequired (this.id + " fetchOrderBook requires an exchange-specific extra 'type' param ('bid' or 'ask') when used with a limit");
} else {
request['items_per_page'] = limit;
}
+3 -3
View File
@@ -362,7 +362,7 @@ module.exports = class indodax extends Exchange {
async fetchOrder (id, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new ExchangeError (this.id + ' fetchOrder requires a symbol');
throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol');
}
await this.loadMarkets ();
const market = this.market (symbol);
@@ -409,7 +409,7 @@ module.exports = class indodax extends Exchange {
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new ExchangeError (this.id + ' fetchOrders requires a symbol');
throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
}
await this.loadMarkets ();
const request = {};
@@ -458,7 +458,7 @@ module.exports = class indodax extends Exchange {
}
const side = this.safeValue (params, 'side');
if (side === undefined) {
throw new ExchangeError (this.id + ' cancelOrder requires an extra "side" param');
throw new ArgumentsRequired (this.id + ' cancelOrder requires an extra "side" param');
}
await this.loadMarkets ();
const market = this.market (symbol);
+2 -2
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, AuthenticationError } = require ('./base/errors');
const { ExchangeError, AuthenticationError, ArgumentsRequired } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -254,7 +254,7 @@ module.exports = class itbit extends Exchange {
await this.loadMarkets ();
const walletId = this.safeString (params, 'walletId');
if (walletId === undefined) {
throw new ExchangeError (this.id + ' fetchMyTrades requires a walletId parameter');
throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a walletId parameter');
}
const request = {
'walletId': walletId,
+263 -32
View File
@@ -36,6 +36,7 @@ module.exports = class kraken extends Exchange {
'withdraw': true,
'fetchLedgerEntry': true,
'fetchLedger': true,
'fetchOrderTrades': 'emulated',
},
'marketsByAltname': {},
'timeframes': {
@@ -54,7 +55,7 @@ module.exports = class kraken extends Exchange {
'api': {
'public': 'https://api.kraken.com',
'private': 'https://api.kraken.com',
'zendesk': 'https://support.kraken.com/hc/en-us/articles',
'zendesk': 'https://kraken.zendesk.com/api/v2/help_center/en-us/articles', // use the public zendesk api to receive article bodies and bypass new anti-spam protections
},
'www': 'https://www.kraken.com',
'doc': 'https://www.kraken.com/features/api',
@@ -149,9 +150,9 @@ module.exports = class kraken extends Exchange {
'get': [
// we should really refrain from putting fixed fee numbers and stop hardcoding
// we will be using their web APIs to scrape all numbers from these articles
'205893708-What-is-the-minimum-order-size-',
'201396777-What-are-the-deposit-fees-',
'201893608-What-are-the-withdrawal-fees-',
'205893708', // -What-is-the-minimum-order-size-
'360000292886', // -What-are-the-deposit-fees-
'201893608', // -What-are-the-withdrawal-fees-
],
},
'public': {
@@ -234,12 +235,14 @@ module.exports = class kraken extends Exchange {
return this.decimalToPrecision (fee, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES);
}
async fetchMinOrderAmounts () {
const html = await this.zendeskGet205893708WhatIsTheMinimumOrderSize ();
async fetchMinOrderAmounts (params = {}) {
const response = await this.zendeskGet205893708 (params);
const article = this.safeValue (response, 'article');
const html = this.safeString (article, 'body');
const parts = html.split ('<td class="wysiwyg-text-align-right">');
const numParts = parts.length;
if (numParts < 3) {
throw new NotSupported (this.id + ' fetchMinOrderAmounts HTML page markup has changed: https://support.kraken.com/hc/en-us/articles/205893708-What-is-the-minimum-order-size-');
throw new NotSupported (this.id + ' fetchMinOrderAmounts HTML page markup has changed: https://kraken.zendesk.com/api/v2/help_center/en-us/articles/205893708');
}
const result = {};
// skip the part before the header and the header itself
@@ -262,6 +265,52 @@ module.exports = class kraken extends Exchange {
async fetchMarkets (params = {}) {
const response = await this.publicGetAssetPairs (params);
//
// {
// "error":[],
// "result":{
// "ADAETH":{
// "altname":"ADAETH",
// "wsname":"ADA\/ETH",
// "aclass_base":"currency",
// "base":"ADA",
// "aclass_quote":"currency",
// "quote":"XETH",
// "lot":"unit",
// "pair_decimals":7,
// "lot_decimals":8,
// "lot_multiplier":1,
// "leverage_buy":[],
// "leverage_sell":[],
// "fees":[
// [0,0.26],
// [50000,0.24],
// [100000,0.22],
// [250000,0.2],
// [500000,0.18],
// [1000000,0.16],
// [2500000,0.14],
// [5000000,0.12],
// [10000000,0.1]
// ],
// "fees_maker":[
// [0,0.16],
// [50000,0.14],
// [100000,0.12],
// [250000,0.1],
// [500000,0.08],
// [1000000,0.06],
// [2500000,0.04],
// [5000000,0.02],
// [10000000,0]
// ],
// "fee_volume_currency":"ZUSD",
// "margin_call":80,
// "margin_stop":40
// },
// }
// }
//
const fetchMinOrderAmounts = this.safeValue (this.options, 'fetchMinOrderAmounts', false);
let limits = {};
if (fetchMinOrderAmounts) {
@@ -441,6 +490,13 @@ module.exports = class kraken extends Exchange {
};
}
parseBidAsk (bidask, priceKey = 0, amountKey = 1) {
const price = this.safeFloat (bidask, priceKey);
const amount = this.safeFloat (bidask, amountKey);
const timestamp = this.safeInteger (bidask, 2);
return [ price, amount, timestamp ];
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -454,7 +510,27 @@ module.exports = class kraken extends Exchange {
request['count'] = limit; // 100
}
const response = await this.publicGetDepth (this.extend (request, params));
const orderbook = response['result'][market['id']];
//
// {
// "error":[],
// "result":{
// "XETHXXBT":{
// "asks":[
// ["0.023480","4.000",1586321307],
// ["0.023490","50.095",1586321306],
// ["0.023500","28.535",1586321302],
// ],
// "bids":[
// ["0.023470","59.580",1586321307],
// ["0.023460","20.000",1586321301],
// ["0.023440","67.832",1586321306],
// ]
// }
// }
// }
//
const result = this.safeValue (response, 'result', {});
const orderbook = this.safeValue (result, market['id']);
return this.parseOrderBook (orderbook);
}
@@ -708,26 +784,46 @@ module.exports = class kraken extends Exchange {
}
parseTrade (trade, market = undefined) {
//
// fetchTrades (public)
//
// [
// "0.032310", // price
// "4.28169434", // amount
// 1541390792.763, // timestamp
// "s", // sell or buy
// "l", // limit or market
// ""
// ]
//
// fetchOrderTrades (private)
//
// {
// id: 'TIMIRG-WUNNE-RRJ6GT', // injected from outside
// ordertxid: 'OQRPN2-LRHFY-HIFA7D',
// postxid: 'TKH2SE-M7IF5-CFI7LT',
// pair: 'USDCUSDT',
// time: 1586340086.457,
// type: 'sell',
// ordertype: 'market',
// price: '0.99860000',
// cost: '22.16892001',
// fee: '0.04433784',
// vol: '22.20000000',
// margin: '0.00000000',
// misc: ''
// }
//
let timestamp = undefined;
let side = undefined;
let type = undefined;
let price = undefined;
let amount = undefined;
let cost = undefined;
let id = undefined;
let order = undefined;
let fee = undefined;
const marketId = this.safeString (trade, 'pair');
const foundMarket = this.findMarketByAltnameOrId (marketId);
let symbol = undefined;
if (foundMarket !== undefined) {
market = foundMarket;
} else if (marketId !== undefined) {
// delisted market ids go here
market = this.getDelistedMarketById (marketId);
}
if (market !== undefined) {
symbol = market['symbol'];
}
if (Array.isArray (trade)) {
timestamp = this.safeTimestamp (trade, 2);
side = (trade[3] === 's') ? 'sell' : 'buy';
@@ -738,17 +834,27 @@ module.exports = class kraken extends Exchange {
if (tradeLength > 6) {
id = this.safeString (trade, 6); // artificially added as per #1794
}
} else if (typeof trade === 'string') {
id = trade;
} else if ('ordertxid' in trade) {
const marketId = this.safeString (trade, 'pair');
const foundMarket = this.findMarketByAltnameOrId (marketId);
if (foundMarket !== undefined) {
market = foundMarket;
} else if (marketId !== undefined) {
// delisted market ids go here
market = this.getDelistedMarketById (marketId);
}
order = trade['ordertxid'];
id = this.safeString2 (trade, 'id', 'postxid');
timestamp = this.safeTimestamp (trade, 'time');
side = trade['type'];
type = trade['ordertype'];
side = this.safeString (trade, 'type');
type = this.safeString (trade, 'ordertype');
price = this.safeFloat (trade, 'price');
amount = this.safeFloat (trade, 'vol');
if ('fee' in trade) {
let currency = undefined;
if (market) {
if (market !== undefined) {
currency = market['quote'];
}
fee = {
@@ -757,6 +863,14 @@ module.exports = class kraken extends Exchange {
};
}
}
if (market !== undefined) {
symbol = market['symbol'];
}
if (price !== undefined) {
if (amount !== undefined) {
cost = price * amount;
}
}
return {
'id': id,
'order': order,
@@ -769,7 +883,7 @@ module.exports = class kraken extends Exchange {
'takerOrMaker': undefined,
'price': price,
'amount': amount,
'cost': price * amount,
'cost': cost,
'fee': fee,
};
}
@@ -986,6 +1100,11 @@ module.exports = class kraken extends Exchange {
const status = this.parseOrderStatus (this.safeString (order, 'status'));
const id = this.safeString (order, 'id');
const clientOrderId = this.safeString (order, 'userref');
const rawTrades = this.safeValue (order, 'trades');
let trades = undefined;
if (rawTrades !== undefined) {
trades = this.parseTrades (rawTrades, market, undefined, undefined, { 'order': id });
}
return {
'id': id,
'clientOrderId': clientOrderId,
@@ -1004,8 +1123,7 @@ module.exports = class kraken extends Exchange {
'average': average,
'remaining': remaining,
'fee': fee,
// 'trades': this.parseTrades (order['trades'], market),
'trades': undefined,
'trades': trades,
};
}
@@ -1026,16 +1144,129 @@ module.exports = class kraken extends Exchange {
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privatePostQueryOrders (this.extend ({
const clientOrderId = this.safeValue2 (params, 'userref', 'clientOrderId');
const request = {
'trades': true, // whether or not to include trades in output (optional, default false)
'txid': id, // do not comma separate a list of ids - use fetchOrdersByIds instead
// 'txid': id, // do not comma separate a list of ids - use fetchOrdersByIds instead
// 'userref': 'optional', // restrict results to given user reference id (optional)
}, params));
const orders = response['result'];
};
let query = params;
if (clientOrderId !== undefined) {
request['userref'] = clientOrderId;
query = this.omit (params, [ 'userref', 'clientOrderId' ]);
} else {
request['txid'] = id;
}
const response = await this.privatePostQueryOrders (this.extend (request, query));
//
// {
// "error":[],
// "result":{
// "OTLAS3-RRHUF-NDWH5A":{
// "refid":null,
// "userref":null,
// "status":"closed",
// "reason":null,
// "opentm":1586822919.3342,
// "closetm":1586822919.365,
// "starttm":0,
// "expiretm":0,
// "descr":{
// "pair":"XBTUSDT",
// "type":"sell",
// "ordertype":"market",
// "price":"0",
// "price2":"0",
// "leverage":"none",
// "order":"sell 0.21804000 XBTUSDT @ market",
// "close":""
// },
// "vol":"0.21804000",
// "vol_exec":"0.21804000",
// "cost":"1493.9",
// "fee":"3.8",
// "price":"6851.5",
// "stopprice":"0.00000",
// "limitprice":"0.00000",
// "misc":"",
// "oflags":"fciq",
// "trades":["TT5UC3-GOIRW-6AZZ6R"]
// }
// }
// }
//
const orders = this.safeValue (response, 'result', []);
const order = this.parseOrder (this.extend ({ 'id': id }, orders[id]));
return this.extend ({ 'info': response }, order);
}
async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
const orderTrades = this.safeValue (params, 'trades');
const tradeIds = [];
if (orderTrades === undefined) {
throw new ArgumentsRequired (this.id + " fetchOrderTrades requires a unified order structure in the params argument or a 'trades' param (an array of trade id strings)");
} else {
for (let i = 0; i < orderTrades.length; i++) {
const orderTrade = orderTrades[i];
if (typeof orderTrade === 'string') {
tradeIds.push (orderTrade);
} else {
tradeIds.push (orderTrade['id']);
}
}
}
await this.loadMarkets ();
const options = this.safeValue (this.options, 'fetchOrderTrades', {});
const batchSize = this.safeInteger (options, 'batchSize', 20);
let numBatches = parseInt (tradeIds / batchSize);
numBatches = this.sum (numBatches, 1);
const numTradeIds = tradeIds.length;
let result = [];
for (let j = 0; j < numBatches; j++) {
const requestIds = [];
for (let k = 0; k < batchSize; k++) {
const index = this.sum (j * batchSize, k);
if (index < numTradeIds) {
requestIds.push (tradeIds[index]);
}
}
const request = {
'txid': requestIds.join (','),
};
const response = await this.privatePostQueryTrades (request);
//
// {
// error: [],
// result: {
// 'TIMIRG-WUNNE-RRJ6GT': {
// ordertxid: 'OQRPN2-LRHFY-HIFA7D',
// postxid: 'TKH2SE-M7IF5-CFI7LT',
// pair: 'USDCUSDT',
// time: 1586340086.457,
// type: 'sell',
// ordertype: 'market',
// price: '0.99860000',
// cost: '22.16892001',
// fee: '0.04433784',
// vol: '22.20000000',
// margin: '0.00000000',
// misc: ''
// }
// }
// }
//
const rawTrades = this.safeValue (response, 'result');
const ids = Object.keys (rawTrades);
for (let i = 0; i < ids.length; i++) {
rawTrades[ids[i]]['id'] = ids[i];
}
const trades = this.parseTrades (rawTrades, undefined, since, limit);
const tradesFilteredBySymbol = this.filterBySymbol (trades, symbol);
result = this.arrayConcat (result, tradesFilteredBySymbol);
}
return result;
}
async fetchOrdersByIds (ids, symbol = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privatePostQueryOrders (this.extend ({
@@ -1248,11 +1479,11 @@ module.exports = class kraken extends Exchange {
}
async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
// https://www.kraken.com/en-us/help/api#deposit-status
if (code === undefined) {
throw new ArgumentsRequired (this.id + ' fetchDeposits requires a currency code argument');
}
await this.loadMarkets ();
const currency = this.currency (code);
const request = {
'asset': currency['id'],
@@ -1275,11 +1506,11 @@ module.exports = class kraken extends Exchange {
}
async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
// https://www.kraken.com/en-us/help/api#withdraw-status
if (code === undefined) {
throw new ArgumentsRequired (this.id + ' fetchWithdrawals requires a currency code argument');
}
await this.loadMarkets ();
const currency = this.currency (code);
const request = {
'asset': currency['id'],
@@ -1328,7 +1559,7 @@ module.exports = class kraken extends Exchange {
}
method = this.options['depositMethods'][code][0]['method'];
} else {
throw new ExchangeError (this.id + ' fetchDepositAddress() requires an extra `method` parameter. Use fetchDepositMethods ("' + code + '") to get a list of available deposit methods or enable the exchange property .options["cacheDepositMethodsOnFetchDepositAddress"] = true');
throw new ArgumentsRequired (this.id + ' fetchDepositAddress() requires an extra `method` parameter. Use fetchDepositMethods ("' + code + '") to get a list of available deposit methods or enable the exchange property .options["cacheDepositMethodsOnFetchDepositAddress"] = true');
}
}
const request = {
+121 -41
View File
@@ -69,7 +69,9 @@ module.exports = class kucoin extends Exchange {
'public': {
'get': [
'timestamp',
'status',
'symbols',
'markets',
'market/allTickers',
'market/orderbook/level{level}',
'market/orderbook/level2',
@@ -81,6 +83,9 @@ module.exports = class kucoin extends Exchange {
'market/stats',
'currencies',
'currencies/{currency}',
'prices',
'mark-price/{symbol}/current',
'margin/config',
],
'post': [
'bullet-public',
@@ -92,6 +97,10 @@ module.exports = class kucoin extends Exchange {
'accounts/{accountId}',
'accounts/{accountId}/ledgers',
'accounts/{accountId}/holds',
'accounts/transferable',
'sub/user',
'sub-accounts',
'sub-accounts/{subUserId}',
'deposit-addresses',
'deposits',
'hist-deposits',
@@ -101,8 +110,20 @@ module.exports = class kucoin extends Exchange {
'withdrawals/quotas',
'orders',
'orders/{orderId}',
'limit/orders',
'fills',
'limit/fills',
'margin/account',
'margin/borrow',
'margin/borrow/outstanding',
'margin/borrow/borrow/repaid',
'margin/lend/active',
'margin/lend/done',
'margin/lend/trade/unsettled',
'margin/lend/trade/settled',
'margin/lend/assets',
'margin/market',
'margin/margin/trade/last',
],
'post': [
'accounts',
@@ -111,11 +132,19 @@ module.exports = class kucoin extends Exchange {
'deposit-addresses',
'withdrawals',
'orders',
'orders/multi',
'margin/borrow',
'margin/repay/all',
'margin/repay/single',
'margin/lend',
'margin/toggle-auto-lend',
'bullet-private',
],
'delete': [
'withdrawals/{withdrawalId}',
'orders',
'orders/{orderId}',
'margin/lend/{orderId}',
],
},
},
@@ -247,18 +276,20 @@ module.exports = class kucoin extends Exchange {
async fetchMarkets (params = {}) {
const response = await this.publicGetSymbols (params);
//
// { quoteCurrency: 'BTC',
// symbol: 'KCS-BTC',
// quoteMaxSize: '9999999',
// quoteIncrement: '0.000001',
// baseMinSize: '0.01',
// quoteMinSize: '0.00001',
// enableTrading: true,
// priceIncrement: '0.00000001',
// name: 'KCS-BTC',
// baseIncrement: '0.01',
// baseMaxSize: '9999999',
// baseCurrency: 'KCS' }
// {
// quoteCurrency: 'BTC',
// symbol: 'KCS-BTC',
// quoteMaxSize: '9999999',
// quoteIncrement: '0.000001',
// baseMinSize: '0.01',
// quoteMinSize: '0.00001',
// enableTrading: true,
// priceIncrement: '0.00000001',
// name: 'KCS-BTC',
// baseIncrement: '0.01',
// baseMaxSize: '9999999',
// baseCurrency: 'KCS'
// }
//
const data = response['data'];
const result = [];
@@ -344,20 +375,27 @@ module.exports = class kucoin extends Exchange {
async fetchAccounts (params = {}) {
const response = await this.privateGetAccounts (params);
//
// { code: "200000",
// data: [ { balance: "0.00009788",
// {
// code: "200000",
// data: [
// {
// balance: "0.00009788",
// available: "0.00009788",
// holds: "0",
// currency: "BTC",
// id: "5c6a4fd399a1d81c4f9cc4d0",
// type: "trade" },
// ...,
// { balance: "0.00000001",
// holds: "0",
// currency: "BTC",
// id: "5c6a4fd399a1d81c4f9cc4d0",
// type: "trade"
// },
// {
// balance: "0.00000001",
// available: "0.00000001",
// holds: "0",
// currency: "ETH",
// id: "5c6a49ec99a1d819392e8e9f",
// type: "trade" } ] }
// holds: "0",
// currency: "ETH",
// id: "5c6a49ec99a1d819392e8e9f",
// type: "trade"
// }
// ]
// }
//
const data = this.safeValue (response, 'data');
const result = [];
@@ -641,30 +679,72 @@ module.exports = class kucoin extends Exchange {
};
}
async fetchL3OrderBook (symbol, limit = undefined, params = {}) {
return await this.fetchOrderBook (symbol, limit, { 'level': 3 });
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
let level = '2';
if (limit !== undefined) {
if ((limit !== 20) && (limit !== 100)) {
throw new ExchangeError (this.id + ' fetchOrderBook limit argument must be undefined, 20 or 100');
const level = this.safeInteger (params, 'level', 2);
let levelLimit = level.toString ();
if (level === '2') {
if (limit !== undefined) {
if ((limit !== 20) && (limit !== 100)) {
throw new ExchangeError (this.id + ' fetchOrderBook limit argument must be undefined, 20 or 100');
}
levelLimit += '_' + limit.toString ();
}
level += '_' + limit.toString ();
}
await this.loadMarkets ();
const marketId = this.marketId (symbol);
const request = this.extend ({ 'symbol': marketId, 'level': level }, params);
const response = await this.publicGetMarketOrderbookLevelLevel (request);
const request = { 'symbol': marketId, 'level': levelLimit };
const response = await this.publicGetMarketOrderbookLevelLevel (this.extend (request, params));
//
// { sequence: '1547731421688',
// asks: [ [ '5c419328ef83c75456bd615c', '0.9', '0.09' ], ... ],
// bids: [ [ '5c419328ef83c75456bd615c', '0.9', '0.09' ], ... ], }
// 'market/orderbook/level2'
// 'market/orderbook/level2_20'
// 'market/orderbook/level2_100'
//
const data = response['data'];
// {
// "code":"200000",
// "data":{
// "sequence":"1583235112106",
// "asks":[
// // ...
// ["0.023197","12.5067468"],
// ["0.023194","1.8"],
// ["0.023191","8.1069672"]
// ],
// "bids":[
// ["0.02319","1.6000002"],
// ["0.023189","2.2842325"],
// ],
// "time":1586584067274
// }
// }
//
// 'market/orderbook/level3'
//
// {
// "code":"200000",
// "data":{
// "sequence":"1583731857120",
// "asks":[
// // id, price, size, timestamp in nanoseconds
// ["5e915f8acd26670009675300","6925.7","0.2","1586585482194286069"],
// ["5e915f8ace35a200090bba48","6925.7","0.001","1586585482229569826"],
// ["5e915f8a8857740009ca7d33","6926","0.00001819","1586585482149148621"],
// ],
// "bids":[
// ["5e915f8acca406000ac88194","6925.6","0.05","1586585482384384842"],
// ["5e915f93cd26670009676075","6925.6","0.08","1586585491334914600"],
// ["5e915f906aa6e200099b49f6","6925.4","0.2","1586585488941126340"],
// ],
// "time":1586585492487
// }
// }
//
const data = this.safeValue (response, 'data', {});
const timestamp = this.safeInteger (data, 'time');
// level can be a string such as 2_20 or 2_100
const levelString = this.safeString (request, 'level');
const levelParts = levelString.split ('_');
const offset = parseInt (levelParts[0]);
const orderbook = this.parseOrderBook (data, timestamp, 'bids', 'asks', offset - 2, offset - 1);
const orderbook = this.parseOrderBook (data, timestamp, 'bids', 'asks', level - 2, level - 1);
orderbook['nonce'] = this.safeInteger (data, 'sequence');
return orderbook;
}
@@ -715,7 +795,7 @@ module.exports = class kucoin extends Exchange {
'datetime': this.iso8601 (timestamp),
'fee': undefined,
'status': 'open',
'clientOid': clientOid,
'clientOrderId': clientOid,
'info': data,
};
if (!this.safeValue (params, 'quoteAmount')) {
+21 -1
View File
@@ -18,11 +18,12 @@ module.exports = class kuna extends acx {
'has': {
'CORS': false,
'fetchTickers': true,
'fetchOHLCV': false,
'fetchOHLCV': 'emulated',
'fetchOpenOrders': true,
'fetchMyTrades': true,
'withdraw': false,
},
'timeframes': undefined,
'urls': {
'referral': 'https://kuna.io?r=kunaid-gvfihe8az7o4',
'logo': 'https://user-images.githubusercontent.com/1294454/31697638-912824fa-b3c1-11e7-8c36-cf9606eb94ac.jpg',
@@ -191,4 +192,23 @@ module.exports = class kuna extends acx {
const response = await this.privateGetTradesMy (this.extend (request, params));
return this.parseTrades (response, market, since, limit);
}
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limits = undefined, params = {}) {
await this.loadMarkets ();
const trades = await this.fetchTrades (symbol, since, limits, params);
const ohlcvc = this.buildOHLCVC (trades, timeframe, since, limits);
const result = [];
for (let i = 0; i < ohlcvc.length; i++) {
const ohlcv = ohlcvc[i];
result.push ([
ohlcv[0],
ohlcv[1],
ohlcv[2],
ohlcv[3],
ohlcv[4],
ohlcv[5],
]);
}
return result;
}
};
+59 -22
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError } = require ('./base/errors');
const { ExchangeError, AuthenticationError, BadSymbol, InvalidOrder, InsufficientFunds } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -14,6 +14,7 @@ module.exports = class lakebtc extends Exchange {
'name': 'LakeBTC',
'countries': [ 'US' ],
'version': 'api_v2',
'rateLimit': 1000,
'has': {
'CORS': true,
'createMarketOrder': false,
@@ -55,6 +56,14 @@ module.exports = class lakebtc extends Exchange {
'taker': 0.2 / 100,
},
},
'exceptions': {
'broad': {
'Signature': AuthenticationError,
'invalid symbol': BadSymbol,
'Volume doit': InvalidOrder,
'insufficient_balance': InsufficientFunds,
},
},
});
}
@@ -248,40 +257,68 @@ module.exports = class lakebtc extends Exchange {
} else {
this.checkRequiredCredentials ();
const nonce = this.nonce ();
const nonceAsString = nonce.toString ();
const requestId = this.seconds ();
let queryParams = '';
if ('params' in params) {
const paramsList = params['params'];
queryParams = paramsList.join (',');
const stringParams = [];
for (let i = 0; i < paramsList.length; i++) {
let param = paramsList[i];
if (typeof paramsList !== 'string') {
param = param.toString ();
}
stringParams.push (param);
}
queryParams = stringParams.join (',');
body = {
'method': path,
'params': params['params'],
'id': requestId,
};
} else {
body = {
'method': path,
'params': '',
'id': requestId,
};
}
const query = this.urlencode ({
'tonce': nonce,
'accesskey': this.apiKey,
'requestmethod': method.toLowerCase (),
'id': nonce,
'method': path,
'params': queryParams,
});
body = this.json ({
'method': path,
'params': queryParams,
'id': nonce,
});
body = this.json (body);
let query = [
'tonce=' + nonceAsString,
'accesskey=' + this.apiKey,
'requestmethod=' + method.toLowerCase (),
'id=' + requestId.toString (),
'method=' + path,
'params=' + queryParams,
];
query = query.join ('&');
const signature = this.hmac (this.encode (query), this.encode (this.secret), 'sha1');
const auth = this.encode (this.apiKey + ':' + signature);
const signature64 = this.decode (this.stringToBase64 (auth));
headers = {
'Json-Rpc-Tonce': nonce.toString (),
'Authorization': 'Basic ' + this.decode (this.stringToBase64 (auth)),
'Json-Rpc-Tonce': nonceAsString,
'Authorization': 'Basic ' + signature64,
'Content-Type': 'application/json',
};
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
const response = await this.fetch2 (path, api, method, params, headers, body);
if ('error' in response) {
throw new ExchangeError (this.id + ' ' + this.json (response));
handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
if (response === undefined) {
return; // fallback to the default error handler
}
//
// {"error":"Failed to submit order: invalid symbol"}
// {"error":"Failed to submit order: La validation a échoué : Volume doit être supérieur ou égal à 1.0"}
// {"error":"Failed to submit order: insufficient_balance"}
//
const feedback = this.id + ' ' + body;
const error = this.safeString (response, 'error');
if (error !== undefined) {
this.throwBroadlyMatchedException (this.exceptions['broad'], error, feedback);
throw new ExchangeError (feedback); // unknown message
}
return response;
}
};
+3 -3
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, DDoSProtection, AuthenticationError, InvalidOrder } = require ('./base/errors');
const { ExchangeError, DDoSProtection, AuthenticationError, InvalidOrder, ArgumentsRequired } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -339,10 +339,10 @@ module.exports = class lbank extends Exchange {
await this.loadMarkets ();
const market = this.market (symbol);
if (since === undefined) {
throw new ExchangeError (this.id + ' fetchOHLCV requires a `since` argument');
throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a `since` argument');
}
if (limit === undefined) {
throw new ExchangeError (this.id + ' fetchOHLCV requires a `limit` argument');
throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a `limit` argument');
}
const request = {
'symbol': market['id'],
+64 -8
View File
@@ -177,7 +177,7 @@ module.exports = class liquid extends Exchange {
}
async fetchMarkets (params = {}) {
const markets = await this.publicGetProducts ();
const spot = await this.publicGetProducts (params);
//
// [
// {
@@ -208,20 +208,69 @@ module.exports = class liquid extends Exchange {
// },
// ]
//
const perpetual = await this.publicGetProducts ({ 'perpetual': '1' });
//
// [
// {
// "id": "603",
// "product_type": "Perpetual",
// "code": "CASH",
// "name": null,
// "market_ask": "1143900",
// "market_bid": "1143250",
// "currency": "JPY",
// "currency_pair_code": "P-BTCJPY",
// "pusher_channel": "product_cash_p-btcjpy_603",
// "taker_fee": "0.0",
// "maker_fee": "0.0",
// "low_market_bid": "1124450.0",
// "high_market_ask": "1151750.0",
// "volume_24h": "0.1756",
// "last_price_24h": "1129850.0",
// "last_traded_price": "1144700.0",
// "last_traded_quantity": "0.014",
// "quoted_currency": "JPY",
// "base_currency": "P-BTC",
// "tick_size": "50.0",
// "perpetual_enabled": true,
// "index_price": "1142636.03935",
// "mark_price": "1143522.18417",
// "funding_rate": "0.00033",
// "fair_price": "1143609.31009",
// "timestamp": "1581558659.195353100",
// },
// ]
//
const currencies = await this.fetchCurrencies ();
const currenciesByCode = this.indexBy (currencies, 'code');
const result = [];
const markets = this.arrayConcat (spot, perpetual);
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
const id = market['id'].toString ();
const baseId = market['base_currency'];
const quoteId = market['quoted_currency'];
const id = this.safeString (market, 'id');
const baseId = this.safeString (market, 'base_currency');
const quoteId = this.safeString (market, 'quoted_currency');
const productType = this.safeString (market, 'product_type');
let type = 'spot';
let spot = true;
let swap = false;
if (productType === 'Perpetual') {
spot = false;
swap = true;
type = 'swap';
}
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
let symbol = undefined;
if (swap) {
symbol = this.safeString (market, 'currency_pair_code');
} else {
symbol = base + '/' + quote;
}
const maker = this.safeFloat (market, 'maker_fee');
const taker = this.safeFloat (market, 'taker_fee');
const active = !market['disabled'];
const disabled = this.safeValue (market, 'disabled', false);
const active = !disabled;
const baseCurrency = this.safeValue (currenciesByCode, base);
const quoteCurrency = this.safeValue (currenciesByCode, quote);
const precision = {
@@ -265,6 +314,9 @@ module.exports = class liquid extends Exchange {
'quote': quote,
'baseId': baseId,
'quoteId': quoteId,
'type': type,
'spot': spot,
'swap': swap,
'maker': maker,
'taker': taker,
'limits': limits,
@@ -393,7 +445,7 @@ module.exports = class liquid extends Exchange {
return this.parseTicker (response, market);
}
parseTrade (trade, market) {
parseTrade (trade, market = undefined) {
// { id: 12345,
// quantity: "6.789",
// price: "98765.4321",
@@ -420,13 +472,17 @@ module.exports = class liquid extends Exchange {
}
}
const id = this.safeString (trade, 'id');
let symbol = undefined;
if (market !== undefined) {
symbol = market['symbol'];
}
return {
'info': trade,
'id': id,
'order': orderId,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'symbol': market['symbol'],
'symbol': symbol,
'type': undefined,
'side': side,
'takerOrMaker': takerOrMaker,
+19 -7
View File
@@ -439,7 +439,18 @@ module.exports = class livecoin extends Exchange {
}
}
let symbol = undefined;
if (market !== undefined) {
const marketId = this.safeString (trade, 'symbol');
if (marketId !== undefined) {
if (marketId in this.markets_by_id) {
market = this.markets_by_id[marketId];
} else {
const [ baseId, quoteId ] = marketId.split ('/');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
symbol = base + '/' + quote;
}
}
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
return {
@@ -460,16 +471,17 @@ module.exports = class livecoin extends Exchange {
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'currencyPair': market['id'],
// orderDesc': 'true', // or 'false', if true then new orders will be first, otherwise old orders will be first.
// 'currencyPair': market['id'],
// 'orderDesc': 'true', // or 'false', if true then new orders will be first, otherwise old orders will be first.
// 'offset': 0, // page offset, position of the first item on the page
};
let market = undefined;
if (symbol !== undefined) {
market = this.market (symbol);
request['currencyPair'] = market['id'];
}
if (limit !== undefined) {
request['limit'] = limit;
}
+3 -3
View File
@@ -399,17 +399,17 @@ module.exports = class mercado extends Exchange {
if (code === 'BRL') {
const account_ref = ('account_ref' in params);
if (!account_ref) {
throw new ExchangeError (this.id + ' requires account_ref parameter to withdraw ' + code);
throw new ArgumentsRequired (this.id + ' requires account_ref parameter to withdraw ' + code);
}
} else if (code !== 'LTC') {
const tx_fee = ('tx_fee' in params);
if (!tx_fee) {
throw new ExchangeError (this.id + ' requires tx_fee parameter to withdraw ' + code);
throw new ArgumentsRequired (this.id + ' requires tx_fee parameter to withdraw ' + code);
}
if (code === 'XRP') {
if (tag === undefined) {
if (!('destination_tag' in params)) {
throw new ExchangeError (this.id + ' requires a tag argument or destination_tag parameter to withdraw ' + code);
throw new ArgumentsRequired (this.id + ' requires a tag argument or destination_tag parameter to withdraw ' + code);
}
} else {
request['destination_tag'] = tag;
+27 -40
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, ExchangeNotAvailable, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol } = require ('./base/errors');
const { ExchangeError, ExchangeNotAvailable, OnMaintenance, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol } = require ('./base/errors');
const { TICK_SIZE, TRUNCATE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -61,6 +61,9 @@ module.exports = class okex extends Exchange {
'doc': 'https://www.okex.com/docs/en/',
'fees': 'https://www.okex.com/pages/products/fees.html',
'referral': 'https://www.okex.com/join/1888677',
'test': {
'rest': 'https://testnet.okex.com',
},
},
'api': {
'general': {
@@ -348,8 +351,9 @@ module.exports = class okex extends Exchange {
'30034': ExchangeError, // { "code": 30034, "message": "exchange ID does not exist" }
'30035': ExchangeError, // { "code": 30035, "message": "trading is not supported in this website" }
'30036': ExchangeError, // { "code": 30036, "message": "no relevant data" }
'30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" }
'30037': ExchangeNotAvailable, // { "code": 30037, "message": "endpoint is offline or unavailable" }
// '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" }
'30038': OnMaintenance, // {"client_oid":"","code":"30038","error_code":"30038","error_message":"Matching engine is being upgraded. Please try in about 1 minute.","message":"Matching engine is being upgraded. Please try in about 1 minute.","order_id":"-1","result":false}
// futures
'32001': AccountSuspended, // { "code": 32001, "message": "futures account suspended" }
'32002': PermissionDenied, // { "code": 32002, "message": "futures account does not exist" }
@@ -792,14 +796,6 @@ module.exports = class okex extends Exchange {
'price': this.safeFloat (market, 'tick_size'),
};
const minAmount = this.safeFloat2 (market, 'min_size', 'base_min_size');
let minPrice = this.safeFloat (market, 'tick_size');
if (precision['price'] !== undefined) {
minPrice = Math.pow (10, -precision['price']);
}
let minCost = undefined;
if (minAmount !== undefined && minPrice !== undefined) {
minCost = minAmount * minPrice;
}
const active = true;
const fees = this.safeValue2 (this.fees, marketType, 'trading', {});
return this.extend (fees, {
@@ -823,11 +819,11 @@ module.exports = class okex extends Exchange {
'max': undefined,
},
'price': {
'min': minPrice,
'min': precision['price'],
'max': undefined,
},
'cost': {
'min': minCost,
'min': precision['price'],
'max': undefined,
},
},
@@ -1360,8 +1356,18 @@ module.exports = class okex extends Exchange {
'instrument_id': market['id'],
'granularity': this.timeframes[timeframe],
};
const duration = this.parseTimeframe (timeframe);
if (since !== undefined) {
if (limit !== undefined) {
request['end'] = this.iso8601 (this.sum (since, limit * duration * 1000));
}
request['start'] = this.iso8601 (since);
} else {
const now = this.milliseconds ();
if (limit !== undefined) {
request['start'] = this.iso8601 (now - limit * duration * 1000);
request['end'] = this.iso8601 (now);
}
}
const response = await this[method] (this.extend (request, params));
//
@@ -1841,28 +1847,7 @@ module.exports = class okex extends Exchange {
// "result":true
// }
//
const timestamp = this.milliseconds ();
const id = this.safeString (response, 'order_id');
return {
'info': response,
'id': id,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'status': undefined,
'symbol': symbol,
'type': type,
'side': side,
'price': price,
'amount': amount,
'filled': undefined,
'remaining': undefined,
'cost': undefined,
'trades': undefined,
'fee': undefined,
'clientOrderId': undefined,
'average': undefined,
};
return this.parseOrder (response, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -2302,9 +2287,11 @@ module.exports = class okex extends Exchange {
}
parseDepositAddresses (addresses) {
const result = [];
const result = {};
for (let i = 0; i < addresses.length; i++) {
result.push (this.parseDepositAddress (addresses[i]));
const address = this.parseDepositAddress (addresses[i]);
const code = address['currency'];
result[code] = address;
}
return result;
}
@@ -2350,11 +2337,11 @@ module.exports = class okex extends Exchange {
// ]
//
const addresses = this.parseDepositAddresses (response);
const numAddresses = addresses.length;
if (numAddresses < 1) {
const address = this.safeValue (addresses, code);
if (address === undefined) {
throw new InvalidAddress (this.id + ' fetchDepositAddress cannot return nonexistent addresses, you should create withdrawal addresses with the exchange website first');
}
return addresses[0];
return address;
}
async withdraw (code, amount, address, tag = undefined, params = {}) {
@@ -2366,7 +2353,7 @@ module.exports = class okex extends Exchange {
}
const fee = this.safeString (params, 'fee');
if (fee === undefined) {
throw new ExchangeError (this.id + " withdraw() requires a `fee` string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set '0'. Withdrawing to external digital asset address requires network transaction fee.");
throw new ArgumentsRequired (this.id + " withdraw() requires a `fee` string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKEx are fee-free, please set '0'. Withdrawing to external digital asset address requires network transaction fee.");
}
const request = {
'currency': currency['id'],
+18 -11
View File
@@ -27,6 +27,7 @@ module.exports = class paymium extends Exchange {
'https://github.com/Paymium/api-documentation',
'https://www.paymium.com/page/developers',
],
'referral': 'https://www.paymium.com/page/sign-up?referral=eDAzPoRQFMvaAB8sf-qj',
},
'api': {
'public': {
@@ -41,12 +42,12 @@ module.exports = class paymium extends Exchange {
},
'private': {
'get': [
'merchant/get_payment/{UUID}',
'merchant/get_payment/{uuid}',
'user',
'user/addresses',
'user/addresses/{btc_address}',
'user/orders',
'user/orders/{UUID}',
'user/orders/{uuid}',
'user/price_alerts',
],
'post': [
@@ -57,7 +58,7 @@ module.exports = class paymium extends Exchange {
'merchant/create_payment',
],
'delete': [
'user/orders/{UUID}/cancel',
'user/orders/{uuid}/cancel',
'user/price_alerts/{id}',
],
},
@@ -204,9 +205,9 @@ module.exports = class paymium extends Exchange {
async cancelOrder (id, symbol = undefined, params = {}) {
const request = {
'UUID': id,
'uuid': id,
};
return await this.privateDeleteUserOrdersUUIDCancel (this.extend (request, params));
return await this.privateDeleteUserOrdersUuidCancel (this.extend (request, params));
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
@@ -220,18 +221,24 @@ module.exports = class paymium extends Exchange {
this.checkRequiredCredentials ();
const nonce = this.nonce ().toString ();
let auth = nonce + url;
headers = {
'Api-Key': this.apiKey,
'Api-Nonce': nonce,
};
if (method === 'POST') {
if (Object.keys (query).length) {
body = this.json (query);
auth += body;
headers['Content-Type'] = 'application/json';
}
} else {
if (Object.keys (query).length) {
const queryString = this.urlencode (query);
auth += queryString;
url += '?' + queryString;
}
}
headers = {
'Api-Key': this.apiKey,
'Api-Signature': this.hmac (this.encode (auth), this.encode (this.secret)),
'Api-Nonce': nonce,
'Content-Type': 'application/json',
};
headers['Api-Signature'] = this.hmac (this.encode (auth), this.encode (this.secret));
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
+2 -1
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, ExchangeNotAvailable, RequestTimeout, AuthenticationError, PermissionDenied, DDoSProtection, InsufficientFunds, OrderNotFound, OrderNotCached, InvalidOrder, AccountSuspended, CancelPending, InvalidNonce } = require ('./base/errors');
const { ExchangeError, ExchangeNotAvailable, RequestTimeout, AuthenticationError, PermissionDenied, DDoSProtection, InsufficientFunds, OrderNotFound, OrderNotCached, InvalidOrder, AccountSuspended, CancelPending, InvalidNonce, OnMaintenance } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -170,6 +170,7 @@ module.exports = class poloniex extends Exchange {
'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.': DDoSProtection,
-1
View File
@@ -17,7 +17,6 @@ module.exports = async (exchange, symbol) => {
'btcalpha', // issue with 404 on a documented endpoint https://travis-ci.org/ccxt/ccxt/builds/643930431#L2213
'bitmex', // an issue with null values,to be resolved later
'cex',
'mandala',
]
if (skippedExchanges.includes (exchange.id)) {
+1 -1
View File
@@ -13,7 +13,7 @@ const log = require ('ololog')
module.exports = async (exchange) => {
const randomSymbols = exchange.symbols.sort (() => 0.5 - Math.random ()).slice (0, 2)
const randomSymbols = exchange.symbols.slice ().sort (() => 0.5 - Math.random ()).slice (0, 2)
const customExchangeParams = ([
'yobit',
'tidex',
-1
View File
@@ -14,7 +14,6 @@ const log = require ('ololog')
module.exports = async (exchange, symbol) => {
const skippedExchanges = [
'mandala',
'rightbtc',
]
-1
View File
@@ -76,7 +76,6 @@ module.exports = (exchange, ticker, method, symbol) => {
'xbtce',
'coss',
'idex',
'mandala',
'mercado',
'okex',
'southxchange', // https://user-images.githubusercontent.com/1294454/59953532-314bea80-9489-11e9-85b3-2a711ca49aa7.png
+5
View File
@@ -25,6 +25,8 @@ assert (toWei ('0.001', 18) === '1000000000000000');
assert (toWei (0.1, 18) === '100000000000000000');
assert (toWei (0.01, 18) === '10000000000000000');
assert (toWei (0.001, 18) === '1000000000000000');
assert (toWei ('0.3323340739', 18) === '332334073900000000');
assert (toWei (0.3323340739, 18) === '332334073900000000');
// let us test that we get the inverse for all these test
assert (fromWei ('1000000000000000000', 18) === 1.0);
@@ -43,6 +45,8 @@ assert (fromWei ('1000000000000000', 18) === 0.001);
assert (fromWei (100000000000000000, 18) === 0.1);
assert (fromWei (10000000000000000, 18) === 0.01);
assert (fromWei (1000000000000000, 18) === 0.001);
assert (fromWei ('332334073900000000', 18) === 0.3323340739);
assert (fromWei (332334073900000000, 18) === 0.3323340739);
// ----------------------------------------------------------------------------
// numberToString
@@ -58,6 +62,7 @@ assert (numberToString (7.9e27) === '7900000000000000000000000000');
assert (numberToString (-12.345) === '-12.345');
assert (numberToString (12.345) === '12.345');
assert (numberToString (0) === '0');
assert (numberToString (7.35946e21) === '7359460000000000000000');
// the following line breaks the test
// see https://github.com/ccxt/ccxt/issues/5744
// assert (numberToString (0.00000001) === '0.00000001');
+3
View File
@@ -370,9 +370,12 @@ let tryAllProxies = async function (exchange, proxies) {
;(async function test () {
if (exchangeSymbol) {
await loadExchange (exchange)
await testSymbol (exchange, exchangeSymbol)
} else {
await tryAllProxies (exchange, proxies)
}
+3 -3
View File
@@ -180,6 +180,9 @@ module.exports = class theocean extends Exchange {
}
async fetchOHLCV (symbol, timeframe = '5m', since = undefined, limit = undefined, params = {}) {
if (since === undefined) {
throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
@@ -187,9 +190,6 @@ module.exports = class theocean extends Exchange {
'quoteTokenAddress': market['quoteId'],
'interval': this.timeframes[timeframe],
};
if (since === undefined) {
throw new ExchangeError (this.id + ' fetchOHLCV requires a since argument');
}
since = parseInt (since);
request['startTime'] = since;
const response = await this.publicGetCandlesticks (this.extend (request, params));
+2 -2
View File
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, InsufficientFunds, OrderNotFound } = require ('./base/errors');
const { ExchangeError, InsufficientFunds, OrderNotFound, ArgumentsRequired } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -460,7 +460,7 @@ module.exports = class tidebit extends Exchange {
const currency = this.currency (code);
const id = this.safeString (params, 'id');
if (id === undefined) {
throw new ExchangeError (this.id + ' withdraw() requires an extra `id` param (withdraw account id according to withdraws/bind_account_list endpoint');
throw new ArgumentsRequired (this.id + ' withdraw() requires an extra `id` param (withdraw account id according to withdraws/bind_account_list endpoint');
}
const request = {
'id': id,
+30 -13
View File
@@ -42,6 +42,7 @@ module.exports = class timex extends Exchange {
'api': 'https://plasma-relay-backend.timex.io',
'www': 'https://timex.io',
'doc': 'https://docs.timex.io',
'referral': 'https://timex.io/?refcode=1x27vNkTbP1uwkCck',
},
'api': {
'custody': {
@@ -892,7 +893,21 @@ module.exports = class timex extends Exchange {
// "active": true,
// "withdrawalFee": "50000000000000000",
// "purchaseCommissions": []
// },
// }
//
// https://github.com/ccxt/ccxt/issues/6878
//
// {
// "symbol":"XRP",
// "name":"Ripple",
// "address":"0x0dc8882914f3ddeebf4cec6dc20edb99df3def6c",
// "decimals":6,
// "tradeDecimals":16,
// "depositEnabled":true,
// "withdrawalEnabled":true,
// "transferEnabled":true,
// "active":true
// }
//
const id = this.safeString (currency, 'symbol');
const code = this.safeCurrencyCode (id);
@@ -901,20 +916,22 @@ module.exports = class timex extends Exchange {
const active = this.safeValue (currency, 'active');
// const fee = this.safeFloat (currency, 'withdrawalFee');
const feeString = this.safeString (currency, 'withdrawalFee');
const feeStringLen = feeString.length;
const tradeDecimals = this.safeInteger (currency, 'tradeDecimals');
let fee = undefined;
const dotIndex = feeStringLen - tradeDecimals;
if (dotIndex > 0) {
const whole = feeString.slice (0, dotIndex);
const fraction = feeString.slice (-dotIndex);
fee = parseFloat (whole + '.' + fraction);
} else {
let fraction = '.';
for (let i = 0; i < -dotIndex; i++) {
fraction += '0';
if ((feeString !== undefined) && (tradeDecimals !== undefined)) {
const feeStringLen = feeString.length;
const dotIndex = feeStringLen - tradeDecimals;
if (dotIndex > 0) {
const whole = feeString.slice (0, dotIndex);
const fraction = feeString.slice (-dotIndex);
fee = parseFloat (whole + '.' + fraction);
} else {
let fraction = '.';
for (let i = 0; i < -dotIndex; i++) {
fraction += '0';
}
fee = parseFloat (fraction + feeString);
}
fee = parseFloat (fraction + feeString);
}
return {
'id': code,
@@ -1105,7 +1122,7 @@ module.exports = class timex extends Exchange {
this.safeFloat (ohlcv, 'high'),
this.safeFloat (ohlcv, 'low'),
this.safeFloat (ohlcv, 'close'),
this.safeFloat (ohlcv, 'volumeQuote'),
this.safeFloat (ohlcv, 'volume'),
];
}
+4 -2
View File
@@ -1324,9 +1324,11 @@ module.exports = class upbit extends Exchange {
}
parseDepositAddresses (addresses) {
const result = [];
const result = {};
for (let i = 0; i < addresses.length; i++) {
result.push (this.parseDepositAddress (addresses[i]));
const address = this.parseDepositAddress (addresses[i]);
const code = address['currency'];
result[code] = address;
}
return result;
}
+2 -1
View File
@@ -167,11 +167,12 @@ module.exports = class yobit extends Exchange {
'api key dont have trade permission': AuthenticationError,
'invalid parameter': InvalidOrder,
'invalid order': InvalidOrder,
'The given order has already been cancelled': InvalidOrder,
'Requests too often': DDoSProtection,
'not available': ExchangeNotAvailable,
'data unavailable': ExchangeNotAvailable,
'external service unavailable': ExchangeNotAvailable,
'Total transaction amount': ExchangeError, // { "success": 0, "error": "Total transaction amount is less than minimal total: 0.00010000"}
'Total transaction amount': InvalidOrder, // { "success": 0, "error": "Total transaction amount is less than minimal total: 0.00010000"}
'Insufficient funds': InsufficientFunds,
'invalid key': AuthenticationError,
'invalid nonce': InvalidNonce, // {"success":0,"error":"invalid nonce (has already been used)"}'
+2 -2
View File
@@ -453,7 +453,7 @@ module.exports = class zb extends Exchange {
async fetchOrders (symbol = undefined, since = undefined, limit = 50, params = {}) {
if (symbol === undefined) {
throw new ExchangeError (this.id + 'fetchOrders requires a symbol parameter');
throw new ArgumentsRequired (this.id + 'fetchOrders requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
@@ -481,7 +481,7 @@ module.exports = class zb extends Exchange {
async fetchOpenOrders (symbol = undefined, since = undefined, limit = 10, params = {}) {
if (symbol === undefined) {
throw new ExchangeError (this.id + 'fetchOpenOrders requires a symbol parameter');
throw new ArgumentsRequired (this.id + 'fetchOpenOrders requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
+14 -15
View File
@@ -1,27 +1,26 @@
{
"_from": "ccxt@1.25.80",
"_id": "ccxt@1.25.80",
"_from": "ccxt@^1.25.80",
"_id": "ccxt@1.27.45",
"_inBundle": false,
"_integrity": "sha512-AUWagxMa8PMexRabbktWezlmVacj6L2Ep4844ebIXUOyME2Ommg7O/9/pq0F2Ne1IHcJnNJzHrMYQvkh2gBtlw==",
"_integrity": "sha512-4ADlbcIWDzIWjtLvsrtux5jMFj7pU4kVuiqtI2Btq6NEhQ4r/4+LirXdEFlCF6/wIU3XSHabxMd/8nu8HC1KJw==",
"_location": "/ccxt",
"_phantomChildren": {},
"_requested": {
"type": "version",
"type": "range",
"registry": true,
"raw": "ccxt@1.25.80",
"raw": "ccxt@^1.25.80",
"name": "ccxt",
"escapedName": "ccxt",
"rawSpec": "1.25.80",
"rawSpec": "^1.25.80",
"saveSpec": null,
"fetchSpec": "1.25.80"
"fetchSpec": "^1.25.80"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.25.80.tgz",
"_shasum": "aee14637402aecc53d8a7d78af78bb7d730c84d5",
"_spec": "ccxt@1.25.80",
"_resolved": "https://registry.npmjs.org/ccxt/-/ccxt-1.27.45.tgz",
"_shasum": "d4470a16dbff881da7fcccd38b0efa277f5a9c37",
"_spec": "ccxt@^1.25.80",
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer",
"author": {
"name": "Igor Kroitor",
@@ -447,8 +446,6 @@
"Binance Jersey",
"bequant.io",
"Bequant",
"mandalaex.com",
"Mandala",
"dx.exchange",
"DX.Exchange",
"oceanex.pro.com",
@@ -491,7 +488,9 @@
"Bybit",
"aofex.com",
"AOFEX",
"byte-trade.com"
"byte-trade.com",
"hbtc.com",
"HBTC"
],
"license": "MIT",
"main": "./ccxt.js",
@@ -539,5 +538,5 @@
},
"types": "./ccxt.d.ts",
"unpkg": "dist/ccxt.browser.js",
"version": "1.25.80"
"version": "1.27.45"
}
+6 -7
View File
@@ -1,27 +1,26 @@
{
"_from": "dotenv@8.2.0",
"_from": "dotenv@^8.2.0",
"_id": "dotenv@8.2.0",
"_inBundle": false,
"_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
"_location": "/dotenv",
"_phantomChildren": {},
"_requested": {
"type": "version",
"type": "range",
"registry": true,
"raw": "dotenv@8.2.0",
"raw": "dotenv@^8.2.0",
"name": "dotenv",
"escapedName": "dotenv",
"rawSpec": "8.2.0",
"rawSpec": "^8.2.0",
"saveSpec": null,
"fetchSpec": "8.2.0"
"fetchSpec": "^8.2.0"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a",
"_spec": "dotenv@8.2.0",
"_spec": "dotenv@^8.2.0",
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer",
"bugs": {
"url": "https://github.com/motdotla/dotenv/issues"
+5
View File
@@ -330,6 +330,11 @@ class TelegrafContext {
return this.telegram.kickChatMember(this.chat.id, ...args)
}
unbanChatMember (...args) {
this.assert(this.chat, 'unbanChatMember')
return this.telegram.unbanChatMember(this.chat.id, ...args)
}
restrictChatMember (...args) {
this.assert(this.chat, 'restrictChatMember')
return this.telegram.restrictChatMember(this.chat.id, ...args)
+85 -45
View File
@@ -164,15 +164,91 @@ class Markup {
}
static formatHTML (text = '', entities = []) {
const chars = ['', ...text.split(''), ''].map(escapeHTMLChar)
entities.forEach(entity => {
const tag = getHTMLTag(entity)
const openPos = entity.offset
const closePos = entity.offset + entity.length + 1
chars[openPos] += tag.open
chars[closePos] = tag.close + chars[closePos]
})
return chars.join('')
const chars = [...text]
const available = [...entities]
const opened = []
const result = []
for (let offset = 0; offset < chars.length; offset++) {
while (true) {
const index = available.findIndex((entity) => entity.offset === offset)
if (index === -1) {
break
}
const entity = available[index]
switch (entity.type) {
case 'bold':
result.push('<b>')
break
case 'italic':
result.push('<i>')
break
case 'code':
result.push('<code>')
break
case 'pre':
if (entity.language) {
result.push(`<pre><code class="language-${entity.language}">`)
} else {
result.push('<pre>')
}
break
case 'strikethrough':
result.push('<s>')
break
case 'underline':
result.push('<u>')
break
case 'text_mention':
result.push(`<a href="tg://user?id=${entity.user.id}">`)
break
case 'text_link':
result.push(`<a href="${entity.url}">`)
break
}
opened.unshift(entity)
available.splice(index, 1)
}
result.push(chars[offset])
while (true) {
const index = opened.findIndex((entity) => entity.offset + entity.length - 1 === offset)
if (index === -1) {
break
}
const entity = opened[index]
switch (entity.type) {
case 'bold':
result.push('</b>')
break
case 'italic':
result.push('</i>')
break
case 'code':
result.push('</code>')
break
case 'pre':
if (entity.language) {
result.push('</code></pre>')
} else {
result.push('</pre>')
}
break
case 'strikethrough':
result.push('</s>')
break
case 'underline':
result.push('</u>')
break
case 'text_mention':
case 'text_link':
result.push('</a>')
break
}
opened.splice(index, 1)
}
}
return result.join('')
}
}
@@ -203,40 +279,4 @@ function buildKeyboard (buttons, options) {
return result
}
function escapeHTMLChar (c) {
switch (c) {
case '&': return '&amp;'
case '"': return '&quot;'
case '\'': return '&#39;'
case '<': return '&lt;'
default : return c
}
}
function tag (name, params) {
return {
open: params
? `<${name} ${Object.entries(params).map(([key, value]) => `${key}="${value.replace(/[<&"]/g, escapeHTMLChar)}"`).join(' ')}>`
: `<${name}>`,
close: `</${name}>`
}
}
const HTMLTags = new Map([
['bold', tag('b')],
['italic', tag('i')],
['code', tag('code')],
['pre', tag('pre')],
['strikethrough', tag('s')],
['underline', tag('u')],
['text_link', ({ url }) => tag('a', { href: url })],
['text_mention', ({ user }) => tag('a', { href: `tg://user?id=${user.id}` })]
])
function getHTMLTag (entity) {
const tag = HTMLTags.get(entity.type || 'unknown')
if (!tag) return { open: '', close: '' }
return typeof tag === 'function' ? tag(entity) : tag
}
module.exports = Markup
+13 -13
View File
@@ -1,34 +1,33 @@
{
"_from": "telegraf@3.37.0",
"_id": "telegraf@3.37.0",
"_from": "telegraf@^3.37.0",
"_id": "telegraf@3.38.0",
"_inBundle": false,
"_integrity": "sha512-V3448qwfOolBqkIc87yxjW4zMvR2P6AIF24pPTlX9WhZPwA1TF/x3nQhnWPRLtGh2SJuvDcr83iTkXPXT7Opnw==",
"_integrity": "sha512-va4VlrKWp64JrowFoZX/NPzzA6q38kvaIukVXOWFO1V+jR1G8+hCfgJy4TX8Z3rwLJzwaBEet1QhikHDRZWl3A==",
"_location": "/telegraf",
"_phantomChildren": {},
"_requested": {
"type": "version",
"type": "range",
"registry": true,
"raw": "telegraf@3.37.0",
"raw": "telegraf@^3.37.0",
"name": "telegraf",
"escapedName": "telegraf",
"rawSpec": "3.37.0",
"rawSpec": "^3.37.0",
"saveSpec": null,
"fetchSpec": "3.37.0"
"fetchSpec": "^3.37.0"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.37.0.tgz",
"_shasum": "f88ae3d4bddac6f479137d4c867489acf3f57b66",
"_spec": "telegraf@3.37.0",
"_resolved": "https://registry.npmjs.org/telegraf/-/telegraf-3.38.0.tgz",
"_shasum": "745b447547a8e6cdb626055e4d616058aaae0759",
"_spec": "telegraf@^3.37.0",
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer",
"author": {
"name": "Vitaly Domnikov",
"email": "oss@vitaly.codes"
},
"bin": {
"telegraf": "bin/telegraf"
"telegraf": "./bin/telegraf"
},
"bugs": {
"url": "https://github.com/telegraf/telegraf/issues"
@@ -55,6 +54,7 @@
"eslint-plugin-promise": "^4.0.0",
"eslint-plugin-standard": "^4.0.0",
"husky": "^4.2.0",
"prettier": "^2.0.5",
"typescript": "^3.0.1"
},
"engines": {
@@ -91,5 +91,5 @@
},
"type": "commonjs",
"types": "./typings/index.d.ts",
"version": "3.37.0"
"version": "3.38.0"
}
+1
View File
@@ -213,6 +213,7 @@ module.exports = Object.assign(Telegraf, {
Extra,
Markup,
Router,
Telegraf,
Telegram,
Stage,
BaseScene,
+1 -18
View File
@@ -92,7 +92,7 @@ function toBuffer(data) {
if (data instanceof ArrayBuffer) {
buf = Buffer.from(data);
} else if (ArrayBuffer.isView(data)) {
buf = viewToBuffer(data);
buf = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
} else {
buf = Buffer.from(data);
toBuffer.readOnly = false;
@@ -101,23 +101,6 @@ function toBuffer(data) {
return buf;
}
/**
* Converts an `ArrayBuffer` view into a buffer.
*
* @param {(DataView|TypedArray)} view The view to convert
* @return {Buffer} Converted view
* @private
*/
function viewToBuffer(view) {
const buf = Buffer.from(view.buffer);
if (view.byteLength !== view.buffer.byteLength) {
return buf.slice(view.byteOffset, view.byteOffset + view.byteLength);
}
return buf;
}
try {
const bufferUtil = require('bufferutil');
const bu = bufferUtil.BufferUtil || bufferUtil;
+22 -15
View File
@@ -109,11 +109,16 @@ const EventTarget = {
/**
* Register an event listener.
*
* @param {String} method A string representing the event type to listen for
* @param {String} type A string representing the event type to listen for
* @param {Function} listener The listener to add
* @param {Object} options An options object specifies characteristics about
* the event listener
* @param {Boolean} options.once A `Boolean`` indicating that the listener
* should be invoked at most once after being added. If `true`, the
* listener would be automatically removed when invoked.
* @public
*/
addEventListener(method, listener) {
addEventListener(type, listener, options) {
if (typeof listener !== 'function') return;
function onMessage(data) {
@@ -132,36 +137,38 @@ const EventTarget = {
listener.call(this, new OpenEvent(this));
}
if (method === 'message') {
const method = options && options.once ? 'once' : 'on';
if (type === 'message') {
onMessage._listener = listener;
this.on(method, onMessage);
} else if (method === 'close') {
this[method](type, onMessage);
} else if (type === 'close') {
onClose._listener = listener;
this.on(method, onClose);
} else if (method === 'error') {
this[method](type, onClose);
} else if (type === 'error') {
onError._listener = listener;
this.on(method, onError);
} else if (method === 'open') {
this[method](type, onError);
} else if (type === 'open') {
onOpen._listener = listener;
this.on(method, onOpen);
this[method](type, onOpen);
} else {
this.on(method, listener);
this[method](type, listener);
}
},
/**
* Remove an event listener.
*
* @param {String} method A string representing the event type to remove
* @param {String} type A string representing the event type to remove
* @param {Function} listener The listener to remove
* @public
*/
removeEventListener(method, listener) {
const listeners = this.listeners(method);
removeEventListener(type, listener) {
const listeners = this.listeners(type);
for (let i = 0; i < listeners.length; i++) {
if (listeners[i] === listener || listeners[i]._listener === listener) {
this.removeListener(method, listeners[i]);
this.removeListener(type, listeners[i]);
}
}
}
+1 -1
View File
@@ -125,8 +125,8 @@ function createWebSocketStream(ws, options) {
if (ws._socket === null) return;
if (ws._socket._writableState.finished) {
if (duplex._readableState.endEmitted) duplex.destroy();
callback();
if (duplex._readableState.endEmitted) duplex.destroy();
} else {
ws._socket.once('finish', function finish() {
// `duplex` is not destroyed here because the `'end'` event will be
+10 -12
View File
@@ -7,10 +7,9 @@ const { createServer, STATUS_CODES } = require('http');
const PerMessageDeflate = require('./permessage-deflate');
const WebSocket = require('./websocket');
const { format, parse } = require('./extension');
const { GUID } = require('./constants');
const { GUID, kWebSocket } = require('./constants');
const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
const kUsedByWebSocketServer = Symbol('kUsedByWebSocketServer');
/**
* Class representing a WebSocket server.
@@ -79,13 +78,6 @@ class WebSocketServer extends EventEmitter {
callback
);
} else if (options.server) {
if (options.server[kUsedByWebSocketServer]) {
throw new Error(
'The HTTP/S server is already being used by another WebSocket server'
);
}
options.server[kUsedByWebSocketServer] = true;
this._server = options.server;
}
@@ -153,8 +145,6 @@ class WebSocketServer extends EventEmitter {
server.close(() => this.emit('close'));
return;
}
delete server[kUsedByWebSocketServer];
}
process.nextTick(emitClose, this);
@@ -264,6 +254,7 @@ class WebSocketServer extends EventEmitter {
* @param {net.Socket} socket The network socket between the server and client
* @param {Buffer} head The first packet of the upgraded stream
* @param {Function} cb Callback
* @throws {Error} If called more than once with the same socket
* @private
*/
completeUpgrade(key, extensions, req, socket, head, cb) {
@@ -272,6 +263,13 @@ class WebSocketServer extends EventEmitter {
//
if (!socket.readable || !socket.writable) return socket.destroy();
if (socket[kWebSocket]) {
throw new Error(
'server.handleUpgrade() was called more than once with the same ' +
'socket, possibly due to a misconfiguration'
);
}
const digest = createHash('sha1')
.update(key + GUID)
.digest('base64');
@@ -386,7 +384,7 @@ function abortHandshake(socket, code, message, headers) {
message = message || STATUS_CODES[code];
headers = {
Connection: 'close',
'Content-type': 'text/html',
'Content-Type': 'text/html',
'Content-Length': Buffer.byteLength(message),
...headers
};
-1
View File
@@ -456,7 +456,6 @@ function initAsClient(websocket, address, protocols, options) {
protocol: undefined,
timeout: undefined,
method: undefined,
auth: undefined,
host: undefined,
path: undefined,
port: undefined
+21 -60
View File
@@ -1,52 +1,38 @@
{
"_args": [
[
"ws@^7.1.2",
"C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer"
]
],
"_from": "ws@>=7.1.2-0 <8.0.0-0",
"_hasShrinkwrap": false,
"_id": "ws@7.2.3",
"_inCache": true,
"_from": "ws@^7.1.2",
"_id": "ws@7.3.0",
"_inBundle": false,
"_integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==",
"_location": "/ws",
"_nodeVersion": "13.10.1",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/ws_7.2.3_1583774852485_0.5683086237203219"
},
"_npmUser": {
"email": "luigipinca@gmail.com",
"name": "lpinca"
},
"_npmVersion": "6.13.7",
"_phantomChildren": {},
"_requested": {
"name": "ws",
"type": "range",
"registry": true,
"raw": "ws@^7.1.2",
"name": "ws",
"escapedName": "ws",
"rawSpec": "^7.1.2",
"scope": null,
"spec": ">=7.1.2-0 <8.0.0-0",
"type": "range"
"saveSpec": null,
"fetchSpec": "^7.1.2"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz",
"_shasum": "a5411e1fb04d5ed0efee76d26d5c46d830c39b46",
"_shrinkwrap": null,
"_resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz",
"_shasum": "4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd",
"_spec": "ws@^7.1.2",
"_where": "C:\\Users\\Luis\\source\\repos\\AAMasters\\TaskServer",
"author": {
"email": "einaros@gmail.com",
"name": "Einar Otto Stangvik",
"email": "einaros@gmail.com",
"url": "http://2x.io"
},
"browser": "browser.js",
"bugs": {
"url": "https://github.com/websockets/ws/issues"
},
"dependencies": {},
"bundleDependencies": false,
"deprecated": false,
"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
"devDependencies": {
"benchmark": "^2.1.4",
@@ -60,19 +46,14 @@
"prettier": "^1.17.0",
"utf-8-validate": "^5.0.2"
},
"directories": {},
"dist": {
"fileCount": 17,
"integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==",
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeZnyFCRA9TVsSAnZWagAAUvwP/jAz5ASUvvHJjDMOS+r/\npDkuV2MoMwz6ccV+qfbVRWUKq9DqnK7bZBApyNlzV2I+APDqLOVU+2BazNKh\nqoTcVHYcBYe5oBIYUvEeSK2qyBCNJUcz2f79lVxWagdcax5nl5tOcW3B8v4X\n9T2hSvSuDNz8vg0uhCnLboZ+F4SPXd3lHwwfcZFkNSjTcRog4W4QNQTEaPbi\noqPawUw/NXDJMFILS2m/rerFnEyrDl4VpoAS9GyitCE31g22N03bCbsmaUMo\nHmFmefATEhmtIExXMDW9JGLL9FtTwVEIAJEfAWqjLt3JeAuWHvYKKd7rU/y1\nwPUQJxwGM1HDYaxbDLXRBVYkOja3YHB5txB8d2lHLt98c5DQ/lZCz1XQIRao\nPv48dpOX2Qg69IpMzSHktoRUJpt+0KkLWUhb7XGVY79kCgqt6ZqYxBs7coae\nOeReUBaKc+yuM3k45sHxyqiKCsw/qejgzScPnmU/BaC32vEdjqpysRNDtfZj\nNmizo+cLoiO8stLVCHGBwpIxegM8aGj3/C8emNEsSFi4rXT6LGHaWvNfv3FR\nVY2/4QZFL/ddUQ3yAOKF4znsHBY2qfbpPJVnW7IyxZ2h39HX3PpITCcYDPzu\nj4LV/wXFESBSre9RANqfPfkJC+A3k0V8eAB0bYQJKImeUAiqkOkYMyrX+2Ea\nHUeL\r\n=aUaH\r\n-----END PGP SIGNATURE-----\r\n",
"shasum": "a5411e1fb04d5ed0efee76d26d5c46d830c39b46",
"tarball": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz",
"unpackedSize": 109814
},
"engines": {
"node": ">=8.3.0"
},
"gitHead": "5fcdc42ef76d2d0ab920aa37631468e6f1066bcd",
"files": [
"browser.js",
"index.js",
"lib/*.js"
],
"greenkeeper": {
"commitMessages": {
"dependencyUpdate": "[pkg] Update ${dependency} to version ${version}",
@@ -80,7 +61,6 @@
}
},
"homepage": "https://github.com/websockets/ws",
"installable": true,
"keywords": [
"HyBi",
"Push",
@@ -91,26 +71,7 @@
],
"license": "MIT",
"main": "index.js",
"maintainers": [
{
"email": "npm@3rd-Eden.com",
"name": "3rdeden"
},
{
"email": "einaros@gmail.com",
"name": "einaros"
},
{
"email": "luigipinca@gmail.com",
"name": "lpinca"
},
{
"email": "npm@3rd-Eden.com",
"name": "v1"
}
],
"name": "ws",
"optionalDependencies": {},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
@@ -132,5 +93,5 @@
"lint": "eslint --ignore-path .gitignore . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\"",
"test": "npm run lint && nyc --reporter=html --reporter=text mocha --throw-deprecation test/*.test.js"
},
"version": "7.2.3"
"version": "7.3.0"
}