UNPKG

ccxt-compiled

Version:

A JavaScript / Python / PHP cryptocurrency trading library with support for 90+ exchanges

370 lines (292 loc) 13.1 kB
'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); }); }); /* ------------------------------------------------------------------------ */