btc-api-node 1.12.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of btc-api-node might be problematic. Click here for more details.
- package/.istanbul.yml +53 -0
- package/.travis.yml +5 -0
- package/CHANGELOG +33 -0
- package/LICENSE.md +21 -0
- package/README.md +211 -0
- package/doc/order.md +160 -0
- package/doc/rest2.md +573 -0
- package/doc/ws2.md +925 -0
- package/examples/bfx.js +26 -0
- package/examples/rest2/order_history.js +29 -0
- package/examples/rest2/symbols.js +15 -0
- package/examples/rest2/tickers.js +24 -0
- package/examples/rest2/trade_history.js +28 -0
- package/examples/ws2/auth.js +31 -0
- package/examples/ws2/calc.js +33 -0
- package/examples/ws2/cancel_all.js +35 -0
- package/examples/ws2/cancel_all_buf.js +39 -0
- package/examples/ws2/candles.js +36 -0
- package/examples/ws2/info_events.js +40 -0
- package/examples/ws2/oc_multi.js +50 -0
- package/examples/ws2/order_books.js +37 -0
- package/examples/ws2/orders.js +67 -0
- package/examples/ws2/ox_multi.js +61 -0
- package/examples/ws2/sequencing.js +23 -0
- package/examples/ws2/ticker.js +20 -0
- package/examples/ws2/trades.js +27 -0
- package/index.js +24 -0
- package/lib/model.js +25 -0
- package/lib/models/alert.js +25 -0
- package/lib/models/balance_info.js +21 -0
- package/lib/models/candle.js +33 -0
- package/lib/models/funding_credit.js +61 -0
- package/lib/models/funding_info.js +16 -0
- package/lib/models/funding_loan.js +64 -0
- package/lib/models/funding_offer.js +60 -0
- package/lib/models/funding_trade.js +33 -0
- package/lib/models/index.js +23 -0
- package/lib/models/margin_info.js +29 -0
- package/lib/models/notification.js +31 -0
- package/lib/models/order.js +288 -0
- package/lib/models/order_book.js +214 -0
- package/lib/models/position.js +43 -0
- package/lib/models/tick.js +83 -0
- package/lib/models/trade.js +43 -0
- package/lib/models/trade_tick.js +29 -0
- package/lib/models/wallet.js +34 -0
- package/lib/transports/rest.js +391 -0
- package/lib/transports/rest2.js +597 -0
- package/lib/transports/ws.js +323 -0
- package/lib/transports/ws2.js +1729 -0
- package/lib/util/gen_auth_sig.js +23 -0
- package/lib/util/index.js +11 -0
- package/lib/util/is_snapshot.js +5 -0
- package/lib/util/nonce.js +5 -0
- package/package.json +39 -0
- package/test/fixtures/response-ticker-funding.json +1 -0
- package/test/fixtures/response-ticker-pairs.json +1 -0
- package/test/fixtures/response-trades-funding.json +1 -0
- package/test/fixtures/response-trades-pairs.json +1 -0
- package/test/fixtures/response-ws-1-orderbook-R0.json +51 -0
- package/test/fixtures/response-ws2-server-order-book-P0.json +1 -0
- package/test/fixtures/response-ws2-server-order-book-P1.json +1 -0
- package/test/fixtures/response-ws2-server-order-book-R0.json +1 -0
- package/test/fixtures/response-ws2-server-ticker-funding.json +1 -0
- package/test/fixtures/response-ws2-server-trades.json +1 -0
- package/test/helpers/test_model.js +71 -0
- package/test/index.js +131 -0
- package/test/lib/models/alert.js +12 -0
- package/test/lib/models/balance_info.js +12 -0
- package/test/lib/models/candle.js +12 -0
- package/test/lib/models/funding_credit.js +17 -0
- package/test/lib/models/funding_info.js +7 -0
- package/test/lib/models/funding_loan.js +17 -0
- package/test/lib/models/funding_offer.js +17 -0
- package/test/lib/models/funding_trade.js +15 -0
- package/test/lib/models/margin_info.js +15 -0
- package/test/lib/models/notification.js +14 -0
- package/test/lib/models/order.js +395 -0
- package/test/lib/models/order_book.js +188 -0
- package/test/lib/models/position.js +15 -0
- package/test/lib/models/tick.js +34 -0
- package/test/lib/models/trade.js +16 -0
- package/test/lib/models/trade_tick.js +14 -0
- package/test/lib/models/wallet.js +14 -0
- package/test/lib/transports/rest-1-integration.js +131 -0
- package/test/lib/transports/rest-2-integration.js +80 -0
- package/test/lib/transports/rest-2-issue-80-argument-length.js +61 -0
- package/test/lib/transports/rest-2-smoke-test.js +49 -0
- package/test/lib/transports/rest-2-unit.js +26 -0
- package/test/lib/transports/rest1.js +152 -0
- package/test/lib/transports/ws-1-handle-channel.js +83 -0
- package/test/lib/transports/ws-1-parsing.js +40 -0
- package/test/lib/transports/ws-1-test.js +275 -0
- package/test/lib/transports/ws2-integration.js +259 -0
- package/test/lib/transports/ws2-unit.js +1295 -0
- package/test/lib/util/is_snapshot.js +20 -0
- package/test/lib/util/nonce.js +20 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const PORT = 1337
|
|
5
|
+
|
|
6
|
+
const assert = require('assert')
|
|
7
|
+
const http = require('http')
|
|
8
|
+
|
|
9
|
+
const RESTv1 = require('../../../lib/transports/rest')
|
|
10
|
+
|
|
11
|
+
describe('rest integration test', () => {
|
|
12
|
+
it('should get the fundingbook asks, zero bids, 100 asks', (done) => {
|
|
13
|
+
const opts = { limit_bids: 0, limit_asks: 10 }
|
|
14
|
+
const bhttp = new RESTv1({ url: `http://localhost:${PORT}` })
|
|
15
|
+
|
|
16
|
+
const testResBody = `
|
|
17
|
+
{"bids":[],"asks":[
|
|
18
|
+
{"rate":"72.25","amount":"67.5","period":30,"timestamp":"1495565109.0","frr":"No"},
|
|
19
|
+
{"rate":"72.2501","amount":"297.58737203","period":2,"timestamp":"1495565054.0","frr":"No"},
|
|
20
|
+
{"rate":"72.2601","amount":"200.0","period":2,"timestamp":"1495565002.0","frr":"No"},
|
|
21
|
+
{"rate":"72.9535","amount":"211.8299","period":2,"timestamp":"1495565037.0","frr":"No"},
|
|
22
|
+
{"rate":"73.0","amount":"1319.59397488","period":30,"timestamp":"1495564972.0","frr":"No"},
|
|
23
|
+
{"rate":"76.0827","amount":"1511.9115692","period":30,"timestamp":"1495564965.0","frr":"Yes"},
|
|
24
|
+
{"rate":"76.0827","amount":"19849.81630455","period":30,"timestamp":"1495564972.0","frr":"Yes"},
|
|
25
|
+
{"rate":"76.0827","amount":"1052.68464219","period":30,"timestamp":"1495564972.0","frr":"Yes"},
|
|
26
|
+
{"rate":"109.5","amount":"55.33131648","period":3,"timestamp":"1495565103.0","frr":"No"},
|
|
27
|
+
{"rate":"153.1999","amount":"134.86","period":2,"timestamp":"1495565106.0","frr":"No"}]}
|
|
28
|
+
`
|
|
29
|
+
const server = http.createServer((req, res) => {
|
|
30
|
+
res.writeHead(200, {
|
|
31
|
+
'Content-Type': 'application/json'
|
|
32
|
+
})
|
|
33
|
+
res.end(testResBody)
|
|
34
|
+
}).listen(PORT, () => {
|
|
35
|
+
bhttp.fundingbook('USD', opts, (err, data) => {
|
|
36
|
+
if (err) throw err
|
|
37
|
+
assert.ok(data)
|
|
38
|
+
assert.equal(data.bids.length, 0)
|
|
39
|
+
assert.equal(data.asks.length, 10)
|
|
40
|
+
server.close()
|
|
41
|
+
done()
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('new_order -- post_only: postonly used and true', (done) => {
|
|
47
|
+
const bhttp = new RESTv1({
|
|
48
|
+
apiKey: 'dummykey',
|
|
49
|
+
apiSecret: 'dummysecret',
|
|
50
|
+
url: `http://localhost:${PORT}`
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const testResBody = '{}'
|
|
54
|
+
const server = http.createServer((req, res) => {
|
|
55
|
+
res.writeHead(200, {
|
|
56
|
+
'Content-Type': 'application/json'
|
|
57
|
+
})
|
|
58
|
+
const payload = JSON.parse(
|
|
59
|
+
Buffer.from(req.headers['x-bfx-payload'], 'base64').toString('ascii')
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
assert.equal(payload['post_only'], true)
|
|
63
|
+
|
|
64
|
+
res.end(testResBody)
|
|
65
|
+
}).listen(PORT, () => {
|
|
66
|
+
bhttp.new_order('btcusd', '0.1', '0.1', 'bitfinex', 'buy', 'exchange limit', false, true, (err, data) => {
|
|
67
|
+
if (err) throw err
|
|
68
|
+
server.close()
|
|
69
|
+
done()
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('new_order -- post_only: postonly not used and hidden true', (done) => {
|
|
75
|
+
const bhttp = new RESTv1({
|
|
76
|
+
apiKey: 'dummykey',
|
|
77
|
+
apiSecret: 'dummysecret',
|
|
78
|
+
url: `http://localhost:${PORT}`
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
const testResBody = '{}'
|
|
82
|
+
const server = http.createServer((req, res) => {
|
|
83
|
+
res.writeHead(200, {
|
|
84
|
+
'Content-Type': 'application/json'
|
|
85
|
+
})
|
|
86
|
+
const payload = JSON.parse(
|
|
87
|
+
Buffer.from(req.headers['x-bfx-payload'], 'base64').toString('ascii')
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
assert.equal(payload['is_hidden'], true)
|
|
91
|
+
assert.equal(payload['post_only'], undefined)
|
|
92
|
+
|
|
93
|
+
res.end(testResBody)
|
|
94
|
+
}).listen(PORT, () => {
|
|
95
|
+
bhttp.new_order('btcusd', '0.1', '0.1', 'bitfinex', 'buy', 'exchange limit', true, (err, data) => {
|
|
96
|
+
if (err) throw err
|
|
97
|
+
server.close()
|
|
98
|
+
done()
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('new_order -- post_only: postonly not used and hidden not used', (done) => {
|
|
104
|
+
const bhttp = new RESTv1({
|
|
105
|
+
apiKey: 'dummykey',
|
|
106
|
+
apiSecret: 'dummysecret',
|
|
107
|
+
url: `http://localhost:${PORT}`
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
const testResBody = '{}'
|
|
111
|
+
const server = http.createServer((req, res) => {
|
|
112
|
+
res.writeHead(200, {
|
|
113
|
+
'Content-Type': 'application/json'
|
|
114
|
+
})
|
|
115
|
+
const payload = JSON.parse(
|
|
116
|
+
Buffer.from(req.headers['x-bfx-payload'], 'base64').toString('ascii')
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
assert.equal(payload['is_hidden'], undefined)
|
|
120
|
+
assert.equal(payload['post_only'], undefined)
|
|
121
|
+
|
|
122
|
+
res.end(testResBody)
|
|
123
|
+
}).listen(PORT, () => {
|
|
124
|
+
bhttp.new_order('btcusd', '0.1', '0.1', 'bitfinex', 'buy', 'exchange limit', (err, data) => {
|
|
125
|
+
if (err) throw err
|
|
126
|
+
server.close()
|
|
127
|
+
done()
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const assert = require('assert')
|
|
5
|
+
const RESTv2 = require('../../../lib/transports/rest2')
|
|
6
|
+
const { MockRESTv2Server } = require('bfx-api-mock-srv')
|
|
7
|
+
|
|
8
|
+
const getTestREST2 = () => {
|
|
9
|
+
return new RESTv2({
|
|
10
|
+
apiKey: 'dummy',
|
|
11
|
+
apiSecret: 'dummy',
|
|
12
|
+
url: 'http://localhost:9999'
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
it('trades: fetches expected data', (done) => {
|
|
17
|
+
const srv = new MockRESTv2Server({ listen: true })
|
|
18
|
+
const r = getTestREST2()
|
|
19
|
+
srv.setResponse('trades.BTCUSD.0.10.50', [42])
|
|
20
|
+
|
|
21
|
+
r.trades('BTCUSD', 0, 10, 50, (err, res) => {
|
|
22
|
+
if (err) return done(err)
|
|
23
|
+
|
|
24
|
+
assert.deepEqual(res, [42])
|
|
25
|
+
srv.close().then(done).catch(done)
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
describe('RESTv2 integration (mock server) tests', () => {
|
|
30
|
+
// [rest2MethodName, finalMockResponseKey, rest2MethodArgs]
|
|
31
|
+
const methods = [
|
|
32
|
+
// public
|
|
33
|
+
['ticker', 'ticker.BTCUSD', ['BTCUSD']],
|
|
34
|
+
['tickers', 'tickers', [['tBTCUSD', 'tETHUSD']]],
|
|
35
|
+
['stats', 'stats.key.context', ['key', 'context']],
|
|
36
|
+
['candles', 'candles.trade:30m:tBTCUSD.hist', [{ timeframe: '30m', symbol: 'tBTCUSD', section: 'hist' }]],
|
|
37
|
+
|
|
38
|
+
// private
|
|
39
|
+
['alertList', 'alerts.price', ['price']],
|
|
40
|
+
['alertSet', 'alert_set.type.symbol.price', ['type', 'symbol', 'price']],
|
|
41
|
+
['alertDelete', 'alert_del.symbol.price', ['symbol', 'price']],
|
|
42
|
+
['trades', 'trades.BTCUSD.0.10.50', ['BTCUSD', 0, 10, 50]],
|
|
43
|
+
['wallets', 'wallets'],
|
|
44
|
+
['activeOrders', 'active_orders'],
|
|
45
|
+
['orderHistory', 'orders.sym.start.end.limit', ['sym', 'start', 'end', 'limit']],
|
|
46
|
+
['positions'],
|
|
47
|
+
['fundingOffers', 'f_offers.sym', ['sym']],
|
|
48
|
+
['fundingOfferHistory', 'f_offer_hist.sym.start.end.limit', ['sym', 'start', 'end', 'limit']],
|
|
49
|
+
['fundingLoans', 'f_loans.sym', ['sym']],
|
|
50
|
+
['fundingLoanHistory', 'f_loan_hist.sym.start.end.limit', ['sym', 'start', 'end', 'limit']],
|
|
51
|
+
['fundingCredits', 'f_credits.sym', ['sym']],
|
|
52
|
+
['fundingCreditHistory', 'f_credit_hist.sym.start.end.limit', ['sym', 'start', 'end', 'limit']],
|
|
53
|
+
['fundingTrades', 'f_trade_hist.sym.start.end.limit', ['sym', 'start', 'end', 'limit']],
|
|
54
|
+
['marginInfo', 'margin_info.k', ['k']],
|
|
55
|
+
['fundingInfo', 'f_info.k', ['k']],
|
|
56
|
+
['performance'],
|
|
57
|
+
['calcAvailableBalance', 'calc.sym.dir.rate.type', ['sym', 'dir', 'rate', 'type']]
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
methods.forEach((m) => {
|
|
61
|
+
const name = m[0]
|
|
62
|
+
const dataKey = m[1] || m[0]
|
|
63
|
+
const args = m[2] || []
|
|
64
|
+
|
|
65
|
+
it(`${name}: fetches expected data`, (done) => {
|
|
66
|
+
const srv = new MockRESTv2Server({ listen: true })
|
|
67
|
+
const r = getTestREST2()
|
|
68
|
+
srv.setResponse(dataKey, [42])
|
|
69
|
+
|
|
70
|
+
args.push((err, res) => {
|
|
71
|
+
if (err) return done(err)
|
|
72
|
+
|
|
73
|
+
assert.deepEqual(res, [42])
|
|
74
|
+
srv.close().then(done).catch(done)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
r[name].apply(r, args)
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
})
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const PORT = 1337
|
|
5
|
+
|
|
6
|
+
const assert = require('assert')
|
|
7
|
+
const http = require('http')
|
|
8
|
+
|
|
9
|
+
const REST2 = require('../../../lib/transports/rest2')
|
|
10
|
+
|
|
11
|
+
const bhttp = new REST2({
|
|
12
|
+
apiKey: 'dummy',
|
|
13
|
+
apiSecret: 'dummy',
|
|
14
|
+
url: `http://localhost:${PORT}`
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const testResBody = `["ente", "gans", "scholle"]`
|
|
18
|
+
|
|
19
|
+
describe('rest2 api client: issue 80 - argumment length auth request', () => {
|
|
20
|
+
it('errors if no payload defined', (done) => {
|
|
21
|
+
const server = http.createServer((req, res) => {
|
|
22
|
+
res.writeHead(200, {
|
|
23
|
+
'Content-Type': 'text/plain'
|
|
24
|
+
})
|
|
25
|
+
res.end(testResBody)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
server.listen(PORT, () => {
|
|
29
|
+
bhttp.genericCallback = (err) => {
|
|
30
|
+
assert.ok(err)
|
|
31
|
+
|
|
32
|
+
server.close()
|
|
33
|
+
done()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
bhttp._makeAuthRequest('/auth/r/orders', () => {})
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('succeeds with the right argument length', (done) => {
|
|
41
|
+
const server = http.createServer((req, res) => {
|
|
42
|
+
res.writeHead(200, {
|
|
43
|
+
'Content-Type': 'text/plain'
|
|
44
|
+
})
|
|
45
|
+
res.end(testResBody)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
server.listen(PORT, () => {
|
|
49
|
+
bhttp._makeAuthRequest('/auth/r/orders', {}, (err, res) => {
|
|
50
|
+
assert.equal(err, null)
|
|
51
|
+
assert.deepEqual(
|
|
52
|
+
res,
|
|
53
|
+
[ 'ente', 'gans', 'scholle' ]
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
server.close()
|
|
57
|
+
done()
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const PORT = 1337
|
|
5
|
+
|
|
6
|
+
const assert = require('assert')
|
|
7
|
+
const http = require('http')
|
|
8
|
+
const REST2 = require('../../../lib/transports/rest2')
|
|
9
|
+
|
|
10
|
+
const bhttp = new REST2({
|
|
11
|
+
apiKey: 'dummy',
|
|
12
|
+
apiSecret: 'dummy',
|
|
13
|
+
url: `http://localhost:${PORT}`
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const testResBody = `[1765.3,
|
|
17
|
+
0.56800816,
|
|
18
|
+
1767.6,
|
|
19
|
+
1.3874,
|
|
20
|
+
-62.2,
|
|
21
|
+
-0.034,
|
|
22
|
+
1765.3,
|
|
23
|
+
14063.54589155,
|
|
24
|
+
1834.2,
|
|
25
|
+
1726.3 ]`
|
|
26
|
+
|
|
27
|
+
describe('rest2 api client', () => {
|
|
28
|
+
it('gets a response as JSON', (done) => {
|
|
29
|
+
const server = http.createServer((req, res) => {
|
|
30
|
+
res.writeHead(200, {
|
|
31
|
+
'Content-Type': 'text/plain'
|
|
32
|
+
})
|
|
33
|
+
res.end(testResBody)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
server.listen(PORT, () => {
|
|
37
|
+
bhttp.ticker('tBTCUSD', (err, res) => {
|
|
38
|
+
assert.equal(err, null)
|
|
39
|
+
assert.deepEqual(
|
|
40
|
+
res,
|
|
41
|
+
JSON.parse(testResBody)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
server.close()
|
|
45
|
+
done()
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
// const assert = require('assert')
|
|
5
|
+
// const RESTv2 = require('../../../lib/transports/rest2')
|
|
6
|
+
|
|
7
|
+
describe.skip('RESTv2 unit tests', () => {
|
|
8
|
+
it('constructor: applies options')
|
|
9
|
+
it('constructor: provides defaults')
|
|
10
|
+
it('_generateNonce: increments internal nonce')
|
|
11
|
+
|
|
12
|
+
it('_makeAuthRequest: calls cb w/ error on missing arguments')
|
|
13
|
+
it('_makeAuthRequest: POSTs to the specified path')
|
|
14
|
+
it('_makeAuthRequest: includes necessary headers')
|
|
15
|
+
it('_makeAuthRequest: calls cb with an error, or response')
|
|
16
|
+
it('_makeAuthRequest: transforms data if needed')
|
|
17
|
+
|
|
18
|
+
it('_makePublicRequest: GETs the specified path')
|
|
19
|
+
it('_makePublicRequest: calls cb with an error, or response')
|
|
20
|
+
it('_makePublicRequest: transforms data if needed')
|
|
21
|
+
|
|
22
|
+
it('_doTransform: returns empty array for no data')
|
|
23
|
+
it('_doTransform: returns data if unable to transform')
|
|
24
|
+
it('_doTransform: returns array of models for snapshots')
|
|
25
|
+
it('_doTransform: returns single model')
|
|
26
|
+
})
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/* eslint-env mocha */
|
|
3
|
+
/* eslint camelcase: "off" */
|
|
4
|
+
/* eslint-disable no-unused-expressions */
|
|
5
|
+
|
|
6
|
+
const assert = require('assert')
|
|
7
|
+
const { expect } = require('chai')
|
|
8
|
+
const DNS = require('dns')
|
|
9
|
+
const RESTv1 = require('../../../lib/transports/rest')
|
|
10
|
+
const _ = require('lodash')
|
|
11
|
+
|
|
12
|
+
describe('REST v1', () => {
|
|
13
|
+
let skipPublic = process.env.SKIP_PUBLIC_REST
|
|
14
|
+
|
|
15
|
+
if (!skipPublic) {
|
|
16
|
+
before((done) => {
|
|
17
|
+
DNS.resolve('api.bitfinex.com', (err) => {
|
|
18
|
+
if (err) skipPublic = true
|
|
19
|
+
done()
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe('errors', function () {
|
|
25
|
+
const bfx_rest = new RESTv1()
|
|
26
|
+
this.timeout(5000)
|
|
27
|
+
it('should error out if a bad endpoint is given', () => {
|
|
28
|
+
expect(bfx_rest.make_public_request).to.throw(Error)
|
|
29
|
+
})
|
|
30
|
+
it('should fail on authenticated requests if no api_key and api_secret', () => {
|
|
31
|
+
expect(bfx_rest.account_infos).to.throw(Error)
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
describe('public endpoints', function () {
|
|
36
|
+
const bfx_rest = new RESTv1()
|
|
37
|
+
this.timeout(10000) // bumped from 5k for moments of platform lag
|
|
38
|
+
it('should get a ticker', (done) => {
|
|
39
|
+
if (skipPublic) return done()
|
|
40
|
+
|
|
41
|
+
bfx_rest.ticker('BTCUSD', (error, data) => {
|
|
42
|
+
assert(!error)
|
|
43
|
+
expect(data).to.exist
|
|
44
|
+
expect(_.has(data, ['mid',
|
|
45
|
+
'bid',
|
|
46
|
+
'ask',
|
|
47
|
+
'last_price',
|
|
48
|
+
'low',
|
|
49
|
+
'high',
|
|
50
|
+
'volume',
|
|
51
|
+
'timestamp']))
|
|
52
|
+
done()
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
it('should get the today endpoint', (done) => {
|
|
56
|
+
if (skipPublic) return done()
|
|
57
|
+
|
|
58
|
+
bfx_rest.today('BTCUSD', (error, data) => {
|
|
59
|
+
assert(!error)
|
|
60
|
+
expect(data).to.exist
|
|
61
|
+
done()
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
it('should get the stats', (done) => {
|
|
65
|
+
if (skipPublic) return done()
|
|
66
|
+
|
|
67
|
+
bfx_rest.stats('BTCUSD', (error, data) => {
|
|
68
|
+
assert(!error)
|
|
69
|
+
expect(data).to.exist
|
|
70
|
+
expect(_.has(data[0], ['period', 'volume']))
|
|
71
|
+
expect(_.has(data[1], ['period', 'volume']))
|
|
72
|
+
expect(_.has(data[2], ['period', 'volume']))
|
|
73
|
+
done()
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
it('should get the fundingbook', (done) => {
|
|
77
|
+
if (skipPublic) return done()
|
|
78
|
+
|
|
79
|
+
bfx_rest.fundingbook('USD', (error, data) => {
|
|
80
|
+
assert(!error)
|
|
81
|
+
expect(data).to.exist
|
|
82
|
+
expect(_.has(data, ['bids', 'asks']))
|
|
83
|
+
expect(_.keys(data.bids[0])).is.eql(['rate', 'amount', 'period', 'timestamp', 'frr'])
|
|
84
|
+
expect(_.keys(data.asks[0])).is.eql(['rate', 'amount', 'period', 'timestamp', 'frr'])
|
|
85
|
+
expect(_.every([data.asks[0] + data.bids[0]]), !NaN).ok
|
|
86
|
+
done()
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('should get the orderbook', (done) => {
|
|
91
|
+
if (skipPublic) return done()
|
|
92
|
+
|
|
93
|
+
bfx_rest.orderbook('BTCUSD', (error, data) => {
|
|
94
|
+
assert(!error)
|
|
95
|
+
expect(data).to.exist
|
|
96
|
+
expect(_.keys(data)).is.eql(['bids', 'asks'])
|
|
97
|
+
expect(_.keys(data.bids[0])).is.eql(['price', 'amount', 'timestamp'])
|
|
98
|
+
expect(_.keys(data.asks[0])).is.eql(['price', 'amount', 'timestamp'])
|
|
99
|
+
expect(_.every([data.asks[0] + data.bids[0]]), !NaN).ok
|
|
100
|
+
done()
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
it('should get recent trades', (done) => {
|
|
104
|
+
if (skipPublic) return done()
|
|
105
|
+
|
|
106
|
+
bfx_rest.trades('BTCUSD', (error, data) => {
|
|
107
|
+
assert(!error)
|
|
108
|
+
expect(data).is.an.array
|
|
109
|
+
expect(data.length).to.eql(100)
|
|
110
|
+
expect(_.keys(data[0])).to.eql(['timestamp', 'tid', 'price', 'amount', 'exchange', 'type'])
|
|
111
|
+
expect(
|
|
112
|
+
_.map(_.values(data[0]), (v) => typeof (v))
|
|
113
|
+
).is.eql(['number', 'number', 'string', 'string', 'string', 'string'])
|
|
114
|
+
done()
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
it('should get recent lends', (done) => {
|
|
118
|
+
if (skipPublic) return done()
|
|
119
|
+
|
|
120
|
+
bfx_rest.lends('USD', (error, data) => {
|
|
121
|
+
assert(!error)
|
|
122
|
+
expect(data).to.exist
|
|
123
|
+
expect(data).is.an.array
|
|
124
|
+
expect(data.length).to.eql(50)
|
|
125
|
+
expect(_.keys(data[0])).to.eql(['rate', 'amount_lent', 'amount_used', 'timestamp'])
|
|
126
|
+
expect(
|
|
127
|
+
_.map(_.values(data[0]), (v) => typeof (v))
|
|
128
|
+
).is.eql(['string', 'string', 'string', 'number'])
|
|
129
|
+
done()
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
it('should get symbols', (done) => {
|
|
133
|
+
if (skipPublic) return done()
|
|
134
|
+
|
|
135
|
+
bfx_rest.get_symbols((error, data) => {
|
|
136
|
+
assert(!error)
|
|
137
|
+
expect(data[0]).to.eql('btcusd')
|
|
138
|
+
done()
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
it('should get symbol details', (done) => {
|
|
142
|
+
if (skipPublic) return done()
|
|
143
|
+
|
|
144
|
+
bfx_rest.symbols_details((error, data) => {
|
|
145
|
+
assert(!error)
|
|
146
|
+
expect(data).to.exist
|
|
147
|
+
expect(data[0].pair).to.eql('btcusd')
|
|
148
|
+
done()
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
})
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const assert = require('assert')
|
|
5
|
+
const BfxWs = require('../../../lib/transports/ws.js')
|
|
6
|
+
|
|
7
|
+
const bfxWs = new BfxWs({
|
|
8
|
+
apiKey: 'dummy',
|
|
9
|
+
apiSecret: 'dummy'
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
describe('ws1 channel msg handling', () => {
|
|
13
|
+
it('ws1 transforms & normalizes well - R0 update', (done) => {
|
|
14
|
+
bfxWs._channelMap = {
|
|
15
|
+
32755: { channel: 'book', prec: 'R0', symbol: 'tBTCUSD' }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
bfxWs.once('orderbook', (symbol, data) => {
|
|
19
|
+
assert.deepEqual(data, { price: 2477.1, orderId: 2919111002, amount: 0.0125 })
|
|
20
|
+
done()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
bfxWs._handleChannel([ 32755, 2919111002, 2477.1, 0.0125 ])
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('ws1 transforms & normalizes well - P1 update', (done) => {
|
|
27
|
+
bfxWs._channelMap = {
|
|
28
|
+
182: { channel: 'book', prec: 'P1', symbol: 'tBTCUSD' }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
bfxWs.once('orderbook', (symbol, data) => {
|
|
32
|
+
assert.deepEqual(data, { price: 2494, count: 2, amount: 5.9895 })
|
|
33
|
+
done()
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
bfxWs._handleChannel([ 182, 2494, 2, 5.9895 ])
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('ws1 transforms & normalizes well - P1 snap', (done) => {
|
|
40
|
+
bfxWs._channelMap = {
|
|
41
|
+
39: { channel: 'book', prec: 'P1', symbol: 'tBTCUSD' }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
bfxWs.once('orderbook', (symbol, data) => {
|
|
45
|
+
assert.deepEqual(data[1], { price: 2494, count: 3, amount: 0.14606853 })
|
|
46
|
+
done()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const snap = [ 39, [
|
|
50
|
+
[ 2495, 2, 0.8744 ],
|
|
51
|
+
[ 2494, 3, 0.14606853 ],
|
|
52
|
+
[ 2492, 1, 0.4 ]
|
|
53
|
+
]]
|
|
54
|
+
|
|
55
|
+
bfxWs._handleChannel(snap)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('ws1 transforms & normalizes well - R0 snap', (done) => {
|
|
59
|
+
bfxWs._channelMap = {
|
|
60
|
+
34513: { channel: 'book', prec: 'R0', symbol: 'tBTCUSD' }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
bfxWs.once('orderbook', (symbol, data) => {
|
|
64
|
+
assert.deepEqual(
|
|
65
|
+
data[1],
|
|
66
|
+
{ price: 2494.5, orderId: 2919279471, amount: 0.07288 }
|
|
67
|
+
)
|
|
68
|
+
done()
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const snap = [ 34513, [
|
|
72
|
+
[ 2919278474, 2494.5, 0.07901704 ],
|
|
73
|
+
[ 2919279471, 2494.5, 0.07288 ],
|
|
74
|
+
[ 2919280093, 2494.5, 0.03644 ]
|
|
75
|
+
]]
|
|
76
|
+
|
|
77
|
+
bfxWs._handleChannel(snap)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('ws1 _handleChannel ignores heartbeats')
|
|
81
|
+
it('ws1 _processUserEvent emits data, breaks up snapshots')
|
|
82
|
+
it('ws1 _processTradeEvent emits a single trade for te & tu messages')
|
|
83
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/* eslint-env mocha */
|
|
2
|
+
'use strict'
|
|
3
|
+
|
|
4
|
+
const PORT = 1337
|
|
5
|
+
|
|
6
|
+
const assert = require('assert')
|
|
7
|
+
const WebSocket = require('ws')
|
|
8
|
+
const WSv1 = require('../../../lib/transports/ws')
|
|
9
|
+
|
|
10
|
+
describe('websocket1 parsing non json', () => {
|
|
11
|
+
it('should not crash the client', (done) => {
|
|
12
|
+
const bws = new WSv1({
|
|
13
|
+
apiKey: 'dummy',
|
|
14
|
+
apiSecret: 'dummy',
|
|
15
|
+
url: `ws://localhost:${PORT}`
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
bws.open()
|
|
19
|
+
|
|
20
|
+
const wss = new WebSocket.Server({
|
|
21
|
+
perMessageDeflate: false,
|
|
22
|
+
port: PORT
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
wss.on('connection', function connection (ws) {
|
|
26
|
+
ws.on('message', function incoming (msg) {
|
|
27
|
+
msg = JSON.parse(msg)
|
|
28
|
+
assert.equal(msg.len, '25')
|
|
29
|
+
wss.close()
|
|
30
|
+
done()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
ws.send("HTTP Code 408 - I'm a Tea Pot")
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
bws.on('open', () => {
|
|
37
|
+
bws.subscribeOrderBook('BTCUSD', 'R0')
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
})
|