ccxt-compiled
Version:
A JavaScript / Python / PHP cryptocurrency trading library with support for 90+ exchanges
370 lines (292 loc) • 13.1 kB
JavaScript
'use strict';
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* ------------------------------------------------------------------------ */
const ccxt = require('../../ccxt.js'),
assert = require('assert'),
log = require('ololog'),
ansi = require('ansicolor').nice;
/* ------------------------------------------------------------------------ */
const chai = require('chai').use(require('chai-as-promised')).should();
/* ------------------------------------------------------------------------ */
describe('ccxt base code', () => {
it('safeFloat is robust', (0, _asyncToGenerator3.default)(function* () {
assert.strictEqual(ccxt.safeFloat({ 'float': '1.0' }, 'float'), 1.0);
assert.strictEqual(ccxt.safeFloat({ 'float': '-1.0' }, 'float'), -1.0);
assert.strictEqual(ccxt.safeFloat({ 'float': 1.0 }, 'float'), 1.0);
assert.strictEqual(ccxt.safeFloat({ 'float': 0 }, 'float'), 0);
assert.strictEqual(ccxt.safeFloat({ 'float': undefined }, 'float'), undefined);
assert.strictEqual(ccxt.safeFloat({ 'float': "" }, 'float'), undefined);
assert.strictEqual(ccxt.safeFloat({ 'float': "" }, 'float', 0), 0);
assert.strictEqual(ccxt.safeFloat({}, 'float'), undefined);
assert.strictEqual(ccxt.safeFloat({}, 'float', 0), 0);
}));
it.skip('setTimeout_safe is working', done => {
const start = Date.now();
const calls = [];
const brokenSetTimeout = (done, ms) => {
calls.push({ when: Date.now() - start, ms_asked: ms });
return setTimeout(done, 100); // simulates a defect setTimeout implementation that sleeps wrong time (100ms always in this test)
};
const approxEquals = (a, b) => Math.abs(a - b) <= 10;
// ask to sleep 250ms
ccxt.setTimeout_safe(() => {
assert(approxEquals(calls[0].ms_asked, 250));
assert(approxEquals(calls[1].ms_asked, 150));
assert(approxEquals(calls[2].ms_asked, 50));
done();
}, 250, brokenSetTimeout);
});
it('setTimeout_safe canceling is working', done => {
const brokenSetTimeout = (done, ms) => setTimeout(done, 100); // simulates a defect setTimeout implementation that sleeps wrong time (100ms always in this test)
const clear = ccxt.setTimeout_safe(() => {
throw new Error('shouldnt happen!');
}, 250, brokenSetTimeout);
setTimeout(() => {
clear();
}, 200);
setTimeout(() => {
done();
}, 400);
});
it('timeout() is working', (0, _asyncToGenerator3.default)(function* () {
assert('foo', (yield ccxt.timeout(200, new _promise2.default(function (resolve) {
return setTimeout(function () {
return resolve('foo');
}, 100);
}))));
yield ccxt.timeout(100, _promise2.default.reject('foo')).should.be.rejectedWith('foo');
yield ccxt.timeout(100, new _promise2.default(function (resolve, reject) {
return setTimeout(function () {
return reject('foo');
}, 200);
})).should.be.rejectedWith('request timed out');
}));
it('calculateFee() works', () => {
const price = 100.00;
const amount = 10.00;
const taker = 0.0025;
const maker = 0.0010;
const fees = { taker, maker };
const market = {
'id': 'foobar',
'symbol': 'FOO/BAR',
'base': 'FOO',
'quote': 'BAR',
'taker': taker,
'maker': maker,
'precision': {
'amount': 8,
'price': 8
}
};
const exchange = new ccxt.Exchange({
'id': 'mock',
'markets': {
'FOO/BAR': market
}
});
(0, _keys2.default)(fees).forEach(takerOrMaker => {
const result = exchange.calculateFee(market['symbol'], 'limit', 'sell', amount, price, takerOrMaker, {});
assert.deepEqual(result, {
'type': takerOrMaker,
'currency': 'BAR',
'rate': fees[takerOrMaker],
'cost': fees[takerOrMaker] * amount * price
});
});
});
it('amountToLots works', () => {
const exchange = new ccxt.Exchange({
id: 'mock',
markets: {
'ETH/BTC': { id: 'ETH/BTC', symbol: 'ETH/BTC', base: 'ETH', quote: 'BTC', lot: 0.001, precision: { amount: 4 } },
'BTC/USD': { id: 'BTC/USD', symbol: 'BTC/USD', base: 'BTC', quote: 'USD', lot: 0.005, precision: { amount: 3 } },
'ETH/USD': { id: 'ETH/USD', symbol: 'ETH/USD', base: 'ETH', quote: 'USD', lot: 0.01, precision: { amount: 1 } }
}
});
assert.equal(exchange.amountToLots('ETH/BTC', 0.0011), '0.001');
assert.equal(exchange.amountToLots('ETH/BTC', 0.0009), '0');
assert.equal(exchange.amountToLots('ETH/BTC', 0.12345), '0.123');
assert.equal(exchange.amountToLots('BTC/USD', 1.234), '1.230');
assert.equal(exchange.amountToLots('ETH/USD', 0.01), '0');
assert.equal(exchange.amountToLots('ETH/USD', 1.11), '1.1');
assert.equal(exchange.amountToLots('ETH/USD', 1.123), '1.1');
});
it.skip('rate limiting works', (0, _asyncToGenerator3.default)(function* () {
const calls = [];
const rateLimit = 100;
const capacity = 0;
const numTokens = 0;
const defaultCost = 1;
const delay = 0;
const exchange = new ccxt.Exchange({
id: 'mock',
rateLimit,
enableRateLimit: true,
tokenBucket: { capacity, numTokens, defaultCost, delay },
ping(...args) {
var _this = this;
return (0, _asyncToGenerator3.default)(function* () {
return _this.throttle().then(function () {
return exchange.pong(...args);
});
})();
},
pong(...args) {
return (0, _asyncToGenerator3.default)(function* () {
calls.push({ when: Date.now(), path: args[0], args });
})();
}
});
yield exchange.ping('foo');
yield exchange.ping('bar');
yield exchange.ping('baz');
yield _promise2.default.all([exchange.ping('qux'), exchange.ping('zap'), exchange.ping('lol')]);
assert.deepEqual(calls.map(function (x) {
return x.path;
}), ['foo', 'bar', 'baz', 'qux', 'zap', 'lol']);
log(calls);
calls.reduce(function (prevTime, call) {
log('delta T:', call.when - prevTime);
assert(call.when - prevTime >= rateLimit - 1);
return call.when;
}, 0);
}));
it('getCurrencyUsedOnOpenOrders() works', () => {
const calls = [];
const rateLimit = 100;
const exchange = new ccxt.Exchange({
'orders': [{ status: 'open', symbol: 'ETH/BTC', side: 'sell', price: 200.0, amount: 21.0, remaining: 20.0 }, { status: 'open', symbol: 'ETH/BTC', side: 'buy', price: 200.0, amount: 22.0, remaining: 20.0 }, { status: 'open', symbol: 'ETH/BTC', side: 'sell', price: 200.0, amount: 23.0, remaining: 20.0 }, { status: 'closed', symbol: 'BTC/USD', side: 'sell', price: 10.0, amount: 11.0, remaining: 10.0 }, { status: 'open', symbol: 'BTC/USD', side: 'buy', price: 10.0, amount: 12.0, remaining: 10.0 }, { status: 'open', symbol: 'BTC/USD', side: 'sell', price: 10.0, amount: 13.0, remaining: 10.0 }],
'markets': {
'ETH/BTC': { id: 'ETH/BTC', symbol: 'ETH/BTC', base: 'ETH', quote: 'BTC' },
'BTC/USD': { id: 'BTC/USD', symbol: 'BTC/USD', base: 'BTC', quote: 'USD' }
}
});
assert.equal(exchange.getCurrencyUsedOnOpenOrders('LTC'), 0);
assert.equal(exchange.getCurrencyUsedOnOpenOrders('ETH'), 40);
assert.equal(exchange.getCurrencyUsedOnOpenOrders('USD'), 100);
assert.equal(exchange.getCurrencyUsedOnOpenOrders('BTC'), 4010);
});
it.skip('exchange config extension works', () => {
cost = { min: 0.001, max: 1000 };
precision = { amount: 3 };
const exchange = new ccxt.binance({
'markets': {
'ETH/BTC': { limits: { cost }, precision }
}
});
assert.deepEqual(exchange.markets['ETH/BTC'].limits.cost, cost);
assert.deepEqual(exchange.markets['ETH/BTC'].precision, { price: 6, amount: 3 });
assert.deepEqual(exchange.markets['ETH/BTC'].symbol, 'ETH/BTC');
});
it('aggregate() works', () => {
const bids = [[789.1, 123.0], [789.100, 123.0], [123.0, 456.0], [789.0, 123.0], [789.10, 123.0]];
const asks = [[123.0, 456.0], [789.0, 123.0], [789.10, 123.0]];
assert.deepEqual(ccxt.aggregate(bids.sort()), [[123.0, 456.0], [789.0, 123.0], [789.1, 369.0]]);
assert.deepEqual(ccxt.aggregate(asks.sort()), [[123.0, 456.0], [789.0, 123.0], [789.10, 123.0]]);
assert.deepEqual(ccxt.aggregate([]), []);
});
it('deepExtend() works', () => {
let count = 0;
const values = [{
a: 1,
b: 2,
d: {
a: 1,
b: [],
c: { test1: 123, test2: 321 } },
f: 5,
g: 123,
i: 321,
j: [1, 2]
}, {
b: 3,
c: 5,
d: {
b: { first: 'one', second: 'two' },
c: { test2: 222 } },
e: { one: 1, two: 2 },
f: [{ 'foo': 'bar' }],
g: void 0,
h: /abc/g,
i: null,
j: [3, 4]
}];
const extended = ccxt.deepExtend(...values);
assert.deepEqual({
a: 1,
b: 3,
d: {
a: 1,
b: { first: 'one', second: 'two' },
c: { test1: 123, test2: 222 }
},
f: [{ 'foo': 'bar' }],
g: undefined,
c: 5,
e: { one: 1, two: 2 },
h: /abc/g,
i: null,
j: [3, 4]
}, extended);
assert.deepEqual(ccxt.deepExtend(undefined, undefined, { 'foo': 'bar' }), { 'foo': 'bar' });
});
it('groupBy() works', () => {
const array = [{ 'foo': 'a' }, { 'foo': 'b' }, { 'foo': 'c' }, { 'foo': 'b' }, { 'foo': 'c' }, { 'foo': 'c' }];
assert.deepEqual(ccxt.groupBy(array, 'foo'), {
'a': [{ 'foo': 'a' }],
'b': [{ 'foo': 'b' }, { 'foo': 'b' }],
'c': [{ 'foo': 'c' }, { 'foo': 'c' }, { 'foo': 'c' }]
});
});
it('filterBy() works', () => {
const array = [{ 'foo': 'a' }, { 'foo': undefined }, { 'foo': 'b' }, {}, { 'foo': 'a', 'bar': 'b' }, { 'foo': 'c' }, { 'foo': 'd' }, { 'foo': 'b' }, { 'foo': 'c' }, { 'foo': 'c' }];
assert.deepEqual(ccxt.filterBy(array, 'foo', 'a'), [{ 'foo': 'a' }, { 'foo': 'a', 'bar': 'b' }]);
});
it('truncate() works', () => {
assert.equal(ccxt.truncate(0, 0), 0);
assert.equal(ccxt.truncate(-17.56, 2), -17.56);
assert.equal(ccxt.truncate(17.56, 2), 17.56);
assert.equal(ccxt.truncate(-17.569, 2), -17.56);
assert.equal(ccxt.truncate(17.569, 2), 17.56);
assert.equal(ccxt.truncate(49.9999, 4), 49.9999);
assert.equal(ccxt.truncate(49.99999, 4), 49.9999);
assert.equal(ccxt.truncate(1.670006528897705e-10, 4), 0);
});
it('parseBalance() works', () => {
const exchange = new ccxt.Exchange({
'markets': {
'ETH/BTC': { 'id': 'ETH/BTC', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC' }
}
});
const input = {
'ETH': { 'free': 10, 'used': 10, 'total': 20 },
'ZEC': { 'free': 0, 'used': 0, 'total': 0 }
};
const expected = {
'ETH': { 'free': 10, 'used': 10, 'total': 20 },
'ZEC': { 'free': 0, 'used': 0, 'total': 0 },
'free': {
'ETH': 10,
'ZEC': 0
},
'used': {
'ETH': 10,
'ZEC': 0
},
'total': {
'ETH': 20,
'ZEC': 0
}
};
const actual = exchange.parseBalance(input);
assert.deepEqual(actual, expected);
});
});
/* ------------------------------------------------------------------------ */