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,323 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { EventEmitter } = require('events')
|
|
4
|
+
const debug = require('debug')('bitfinex:ws')
|
|
5
|
+
const WebSocket = require('ws')
|
|
6
|
+
|
|
7
|
+
const { isSnapshot, genAuthSig } = require('../util')
|
|
8
|
+
|
|
9
|
+
const WS_URL = 'wss://api.bitfinex.com/ws/'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Communicates with v1 of the Bitfinex WebSocket API
|
|
13
|
+
*/
|
|
14
|
+
class WSv1 extends EventEmitter {
|
|
15
|
+
/**
|
|
16
|
+
* @param {sting} opts.apiKey
|
|
17
|
+
* @param {string} opts.apiSecret
|
|
18
|
+
* @param {string} opts.url - ws connection url
|
|
19
|
+
*/
|
|
20
|
+
constructor (opts = { apiKey: '', apiSecret: '', url: WS_URL }) {
|
|
21
|
+
super()
|
|
22
|
+
|
|
23
|
+
this._apiKey = opts.apiKey || ''
|
|
24
|
+
this._apiSecret = opts.apiSecret || ''
|
|
25
|
+
this._url = opts.url || WS_URL
|
|
26
|
+
this._channelMap = {} // map channel IDs to events
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
open () {
|
|
30
|
+
this._ws = new WebSocket(this._url)
|
|
31
|
+
|
|
32
|
+
this._ws.on('message', this._onWSMessage.bind(this))
|
|
33
|
+
this._ws.on('open', this._onWSOpen.bind(this))
|
|
34
|
+
this._ws.on('error', this._onWSError.bind(this))
|
|
35
|
+
this._ws.on('close', this._onWSClose.bind(this))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
_onWSMessage (msgJSON, flags) {
|
|
39
|
+
let msg
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
msg = JSON.parse(msgJSON)
|
|
43
|
+
} catch (e) {
|
|
44
|
+
debug('[bfx ws2 error] received invalid json')
|
|
45
|
+
debug('[bfx ws2 error] %j', msgJSON)
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
debug('Received message: %j', msg)
|
|
50
|
+
this.emit('message', msg, flags)
|
|
51
|
+
debug('Emmited message event')
|
|
52
|
+
|
|
53
|
+
// Drop out early if channel data
|
|
54
|
+
if (Array.isArray(msg) || !msg.event) {
|
|
55
|
+
return this._handleChannel(msg)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (msg.event === 'subscribed') {
|
|
59
|
+
debug('Subscription report received')
|
|
60
|
+
this._channelMap[msg.chanId] = msg
|
|
61
|
+
} else if (msg.event === 'auth') {
|
|
62
|
+
if (msg.status !== 'OK') {
|
|
63
|
+
debug('Emitting \'error\' %j', msg)
|
|
64
|
+
this.emit('error', msg)
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this._channelMap[msg.chanId] = { channel: 'auth' }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
debug('Emitting \'%s\' %j', msg.event, msg)
|
|
72
|
+
this.emit(msg.event, msg)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
_handleChannel (msg) {
|
|
76
|
+
// First element of Array is the channelId, the rest is the info.
|
|
77
|
+
const channelId = msg.shift() // Pop the first element
|
|
78
|
+
const event = this._channelMap[channelId]
|
|
79
|
+
|
|
80
|
+
if (msg[0] === 'hb') {
|
|
81
|
+
return debug(`received heartbeat in ${event.channel}`)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (event) {
|
|
85
|
+
debug('Message in \'%s\' channel', event.channel)
|
|
86
|
+
|
|
87
|
+
if (event.channel === 'book') {
|
|
88
|
+
this._processBookEvent(msg, event)
|
|
89
|
+
} else if (event.channel === 'trades') {
|
|
90
|
+
this._processTradeEvent(msg, event)
|
|
91
|
+
} else if (event.channel === 'ticker') {
|
|
92
|
+
this._processTickerEvent(msg, event)
|
|
93
|
+
} else if (event.channel === 'auth') {
|
|
94
|
+
this._processUserEvent(msg)
|
|
95
|
+
} else {
|
|
96
|
+
debug('Message in unknown channel')
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
_processUserEvent (msg) {
|
|
102
|
+
const event = msg[0]
|
|
103
|
+
const data = msg[1]
|
|
104
|
+
|
|
105
|
+
if (Array.isArray(data[0])) {
|
|
106
|
+
data[0].forEach((ele) => {
|
|
107
|
+
debug('Emitting \'%s\' %j', event, ele)
|
|
108
|
+
this.emit(event, ele)
|
|
109
|
+
})
|
|
110
|
+
} else if (data.length) {
|
|
111
|
+
debug('Emitting \'%s\', %j', event, data)
|
|
112
|
+
this.emit(event, data)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
_processTickerEvent (msg, event) {
|
|
117
|
+
if (msg.length > 9) { // Update
|
|
118
|
+
// All values are numbers
|
|
119
|
+
const update = {
|
|
120
|
+
bid: msg[0],
|
|
121
|
+
bidSize: msg[1],
|
|
122
|
+
ask: msg[2],
|
|
123
|
+
askSize: msg[3],
|
|
124
|
+
dailyChange: msg[4],
|
|
125
|
+
dailyChangePerc: msg[5],
|
|
126
|
+
lastPrice: msg[6],
|
|
127
|
+
volume: msg[7],
|
|
128
|
+
high: msg[8],
|
|
129
|
+
low: msg[9]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
debug('Emitting ticker, %s, %j', event.pair, update)
|
|
133
|
+
this.emit('ticker', event.pair, update)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
_processTradeEvent (msg, event) {
|
|
138
|
+
if (isSnapshot(msg)) {
|
|
139
|
+
const snapshot = msg[0].map(el => ({
|
|
140
|
+
seq: el[0],
|
|
141
|
+
timestamp: el[1],
|
|
142
|
+
price: el[2],
|
|
143
|
+
amount: el[3]
|
|
144
|
+
}))
|
|
145
|
+
|
|
146
|
+
debug('Emitting trade snapshot, %s, %j', event.pair, snapshot)
|
|
147
|
+
this.emit('trade', event.pair, snapshot)
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (msg[0] !== 'te' && msg[0] !== 'tu') return
|
|
152
|
+
|
|
153
|
+
// seq is a string, other payload members are nums
|
|
154
|
+
const update = { seq: msg[1] }
|
|
155
|
+
|
|
156
|
+
if (msg[0] === 'te') { // Trade executed
|
|
157
|
+
update.timestamp = msg[2]
|
|
158
|
+
update.price = msg[3]
|
|
159
|
+
update.amount = msg[4]
|
|
160
|
+
} else { // Trade updated
|
|
161
|
+
update.id = msg[2]
|
|
162
|
+
update.timestamp = msg[3]
|
|
163
|
+
update.price = msg[4]
|
|
164
|
+
update.amount = msg[5]
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// See http://docs.bitfinex.com/#trades75
|
|
168
|
+
debug('Emitting trade, %s, %j', event.pair, update)
|
|
169
|
+
this.emit('trade', event.pair, update)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
_processBookEvent (msg, event) {
|
|
173
|
+
// TODO: Maybe break this up into snapshot/normal handlers? Also trade event
|
|
174
|
+
if (!isSnapshot(msg[0]) && msg.length > 2) {
|
|
175
|
+
let update
|
|
176
|
+
|
|
177
|
+
if (event.prec === 'R0') {
|
|
178
|
+
update = {
|
|
179
|
+
price: msg[1],
|
|
180
|
+
orderId: msg[0],
|
|
181
|
+
amount: msg[2]
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
update = {
|
|
185
|
+
price: msg[0],
|
|
186
|
+
count: msg[1],
|
|
187
|
+
amount: msg[2]
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
debug('Emitting orderbook, %s, %j', event.pair, update)
|
|
192
|
+
this.emit('orderbook', event.pair, update)
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
msg = msg[0]
|
|
197
|
+
|
|
198
|
+
if (isSnapshot(msg)) {
|
|
199
|
+
const snapshot = msg.map((el) => {
|
|
200
|
+
if (event.prec === 'R0') {
|
|
201
|
+
return {
|
|
202
|
+
orderId: el[0],
|
|
203
|
+
price: el[1],
|
|
204
|
+
amount: el[2]
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
price: el[0],
|
|
210
|
+
count: el[1],
|
|
211
|
+
amount: el[2]
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
debug('Emitting orderbook snapshot, %s, %j', event.pair, snapshot)
|
|
216
|
+
this.emit('orderbook', event.pair, snapshot)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
close () {
|
|
221
|
+
this._ws.close()
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
_onWSOpen () {
|
|
225
|
+
this._channelMap = {}
|
|
226
|
+
this.emit('open')
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
_onWSError (error) {
|
|
230
|
+
this.emit('error', error)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
_onWSClose () {
|
|
234
|
+
this.emit('close')
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
send (msg) {
|
|
238
|
+
debug('Sending %j', msg)
|
|
239
|
+
this._ws.send(JSON.stringify(msg))
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Subscribe to order book updates. Snapshot will be sent as multiple updates.
|
|
244
|
+
* Event will be emited as `PAIRNAME_book`.
|
|
245
|
+
*
|
|
246
|
+
* @param {string} pair - BTCUSD, LTCUSD or LTCBTC. Default BTCUSD
|
|
247
|
+
* @param {string} precision - price aggregation level (P0 (def), P1, P2, P3)
|
|
248
|
+
* @param {string} length - number of price points. 25 (default) or 100.
|
|
249
|
+
* @see http://docs.bitfinex.com/#order-books
|
|
250
|
+
*/
|
|
251
|
+
subscribeOrderBook (pair = 'BTCUSD', prec = 'P0', len = '25') {
|
|
252
|
+
this.send({
|
|
253
|
+
event: 'subscribe',
|
|
254
|
+
channel: 'book',
|
|
255
|
+
pair,
|
|
256
|
+
prec,
|
|
257
|
+
len
|
|
258
|
+
})
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Subscribe to trades. Snapshot will be sent as multiple updates.
|
|
263
|
+
* Event will be emited as `PAIRNAME_trades`.
|
|
264
|
+
*
|
|
265
|
+
* @param {string} pair - BTCUSD, LTCUSD or LTCBTC. Default BTCUSD
|
|
266
|
+
* @see http://docs.bitfinex.com/#trades75
|
|
267
|
+
*/
|
|
268
|
+
subscribeTrades (pair = 'BTCUSD') {
|
|
269
|
+
this.send({
|
|
270
|
+
event: 'subscribe',
|
|
271
|
+
channel: 'trades',
|
|
272
|
+
pair
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Subscribe to ticker updates. The ticker is a high level overview of the
|
|
278
|
+
* state of the market. It shows you the current best bid and ask, as well as
|
|
279
|
+
* the last trade price.
|
|
280
|
+
*
|
|
281
|
+
* Event will be emited as `PAIRNAME_ticker`.
|
|
282
|
+
*
|
|
283
|
+
* @param {string} - pair BTCUSD, LTCUSD or LTCBTC. Default BTCUSD
|
|
284
|
+
* @see http://docs.bitfinex.com/#ticker76
|
|
285
|
+
*/
|
|
286
|
+
subscribeTicker (pair = 'BTCUSD') {
|
|
287
|
+
this.send({
|
|
288
|
+
event: 'subscribe',
|
|
289
|
+
channel: 'ticker',
|
|
290
|
+
pair
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Unsubscribe from a channel.
|
|
296
|
+
*
|
|
297
|
+
* @param {number} chanId - ID of the channel received on `subscribed` event
|
|
298
|
+
*/
|
|
299
|
+
unsubscribe (chanId) {
|
|
300
|
+
this.send({
|
|
301
|
+
event: 'unsubscribe',
|
|
302
|
+
chanId
|
|
303
|
+
})
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Authenticate the user. Will receive executed traded updates.
|
|
308
|
+
*
|
|
309
|
+
* @see http://docs.bitfinex.com/#wallet-updates
|
|
310
|
+
*/
|
|
311
|
+
auth () {
|
|
312
|
+
const { sig, payload } = genAuthSig(this._apiSecret)
|
|
313
|
+
|
|
314
|
+
this.send({
|
|
315
|
+
event: 'auth',
|
|
316
|
+
apiKey: this._apiKey,
|
|
317
|
+
authSig: sig,
|
|
318
|
+
authPayload: payload
|
|
319
|
+
})
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
module.exports = WSv1
|