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,214 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { EventEmitter } = require('events')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* High level OB model to automatically integrate WS updates & maintain sort
|
|
7
|
+
*/
|
|
8
|
+
class OrderBook extends EventEmitter {
|
|
9
|
+
/**
|
|
10
|
+
* Initializes the order book with an existing snapshot (array form)
|
|
11
|
+
*
|
|
12
|
+
* @param {Array[]} snapshot
|
|
13
|
+
*/
|
|
14
|
+
constructor (snapshot = []) {
|
|
15
|
+
super()
|
|
16
|
+
|
|
17
|
+
if (snapshot && snapshot.length > 0) {
|
|
18
|
+
this.updateFromSnapshot(snapshot)
|
|
19
|
+
} else {
|
|
20
|
+
this.bids = []
|
|
21
|
+
this.asks = []
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
updateFromSnapshot (snapshot) {
|
|
26
|
+
this.bids = []
|
|
27
|
+
this.asks = []
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < snapshot.length; i++) {
|
|
30
|
+
if (snapshot[i][2] < 0) {
|
|
31
|
+
this.asks.push(snapshot[i])
|
|
32
|
+
} else {
|
|
33
|
+
this.bids.push(snapshot[i])
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// snapshots may not be sorted
|
|
38
|
+
this.bids.sort((a, b) => b[0] - a[0])
|
|
39
|
+
this.asks.sort((a, b) => a[0] - b[0])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Integrate an update packet; emits an 'update' event on success
|
|
44
|
+
*
|
|
45
|
+
* @param {Array} entry
|
|
46
|
+
* @return {boolean} success - false if entry doesn't match OB
|
|
47
|
+
*/
|
|
48
|
+
updateWith (entry) {
|
|
49
|
+
const [price, count, amount] = entry
|
|
50
|
+
const side = amount < 0 ? this.asks : this.bids
|
|
51
|
+
let insertIndex = -1
|
|
52
|
+
|
|
53
|
+
for (let i = 0; i < side.length; i++) {
|
|
54
|
+
if (insertIndex === -1 && (
|
|
55
|
+
(amount > 0 && price > side[i][0]) ||
|
|
56
|
+
(amount < 0 && price < side[i][0])
|
|
57
|
+
)) {
|
|
58
|
+
insertIndex = i
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (side[i][0] === price) {
|
|
62
|
+
if (count === 0) { // remove
|
|
63
|
+
side.splice(i, 1)
|
|
64
|
+
} else {
|
|
65
|
+
side[i] = entry // update
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.emit('update', entry)
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// remove unkown
|
|
74
|
+
if (count === 0) {
|
|
75
|
+
this.emit('error', new Error(
|
|
76
|
+
`can't remove unknown price level: ${JSON.stringify(entry)}`
|
|
77
|
+
))
|
|
78
|
+
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// add
|
|
83
|
+
if (insertIndex === -1) {
|
|
84
|
+
side.push(entry)
|
|
85
|
+
} else {
|
|
86
|
+
side.splice(insertIndex, 0, entry)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.emit('update', entry)
|
|
90
|
+
return true
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @return {number} price
|
|
95
|
+
*/
|
|
96
|
+
midPrice () {
|
|
97
|
+
return (this.asks[0][0] + this.bids[0][0]) / 2
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @return {number} spread - top bid/ask difference
|
|
102
|
+
*/
|
|
103
|
+
spread () {
|
|
104
|
+
return this.asks[0][0] - this.bids[0][0]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @return {number} amount - total buy-side volume
|
|
109
|
+
*/
|
|
110
|
+
bidAmount () {
|
|
111
|
+
let amount = 0
|
|
112
|
+
|
|
113
|
+
for (let i = 0; i < this.bids.length; i++) {
|
|
114
|
+
amount += this.bids[i][2]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return amount
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @return {number} amount - total sell-side volume
|
|
122
|
+
*/
|
|
123
|
+
askAmount () {
|
|
124
|
+
let amount = 0
|
|
125
|
+
|
|
126
|
+
for (let i = 0; i < this.asks.length; i++) {
|
|
127
|
+
amount += this.asks[i][2]
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return Math.abs(amount)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @param {number} price
|
|
135
|
+
* @return {Object} entry - unserialized, null if not found
|
|
136
|
+
*/
|
|
137
|
+
getEntry (price) {
|
|
138
|
+
const side = this.asks.length > 0 // pick a side w/ incomplete data
|
|
139
|
+
? price >= this.asks[0][0] ? this.asks : this.bids
|
|
140
|
+
: price <= this.bids[0][0] ? this.bids : this.asks
|
|
141
|
+
|
|
142
|
+
for (let i = 0; i < side.length; i++) {
|
|
143
|
+
if (price === side[i][0]) {
|
|
144
|
+
return OrderBook.unserialize(side[i])
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Modifies an array-format OB in place with an update entry. Sort is not
|
|
153
|
+
* gauranteed!
|
|
154
|
+
*
|
|
155
|
+
* @param {number[][]} ob
|
|
156
|
+
* @param {number[]} entry
|
|
157
|
+
* @return {boolean} success - false if entry doesn't match OB
|
|
158
|
+
*/
|
|
159
|
+
static updateArrayOBWith (ob, entry) {
|
|
160
|
+
const [price, count] = entry
|
|
161
|
+
let insertIndex = -1
|
|
162
|
+
|
|
163
|
+
for (let i = 0; i < ob.length; i++) {
|
|
164
|
+
if (price > ob[i][0] && insertIndex === -1) insertIndex = i
|
|
165
|
+
|
|
166
|
+
if (ob[i][0] === price) {
|
|
167
|
+
if (count === 0) {
|
|
168
|
+
ob.splice(i, 1) // remove existing
|
|
169
|
+
} else {
|
|
170
|
+
ob[i] = entry // update existing
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return true
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// remove unkown
|
|
178
|
+
if (count === 0) return false
|
|
179
|
+
|
|
180
|
+
// add
|
|
181
|
+
if (insertIndex === -1) {
|
|
182
|
+
ob.push(entry)
|
|
183
|
+
} else {
|
|
184
|
+
ob.splice(insertIndex, 0, entry)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return true
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Converts an array order book entry or snapshot to an object, with 'price',
|
|
192
|
+
* 'count', and 'amount' keys on entries
|
|
193
|
+
*
|
|
194
|
+
* @param {number[]|number[][]} arr
|
|
195
|
+
* @return {Object} ob - either a map w/ bids & asks, or single entry object
|
|
196
|
+
*/
|
|
197
|
+
static unserialize (arr) {
|
|
198
|
+
if (Array.isArray(arr[0])) {
|
|
199
|
+
const entries = arr.map(e => OrderBook.unserialize(e))
|
|
200
|
+
const bids = entries.filter(e => e.amount > 0)
|
|
201
|
+
const asks = entries.filter(e => e.amount < 0)
|
|
202
|
+
|
|
203
|
+
return { bids, asks }
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
price: arr[0],
|
|
208
|
+
count: arr[1],
|
|
209
|
+
amount: arr[2]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
module.exports = OrderBook
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Model = require('../model')
|
|
4
|
+
|
|
5
|
+
class Position extends Model {
|
|
6
|
+
serialize () {
|
|
7
|
+
return [
|
|
8
|
+
this.symbol,
|
|
9
|
+
this.status,
|
|
10
|
+
this.amount,
|
|
11
|
+
this.basePrice,
|
|
12
|
+
this.marginFunding,
|
|
13
|
+
this.marginFundingType,
|
|
14
|
+
this.pl,
|
|
15
|
+
this.plPerc,
|
|
16
|
+
this.liquidationPrice,
|
|
17
|
+
this.leverage
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static unserialize (arr) {
|
|
22
|
+
return {
|
|
23
|
+
symbol: arr[0],
|
|
24
|
+
status: arr[1],
|
|
25
|
+
amount: arr[2],
|
|
26
|
+
basePrice: arr[3],
|
|
27
|
+
marginFunding: arr[4],
|
|
28
|
+
marginFundingType: arr[5],
|
|
29
|
+
pl: arr[6],
|
|
30
|
+
plPerc: arr[7],
|
|
31
|
+
liquidationPrice: arr[8],
|
|
32
|
+
leverage: arr[9]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Position.status = {}
|
|
38
|
+
const statuses = ['ACTIVE', 'CLOSED']
|
|
39
|
+
statuses.forEach((s) => {
|
|
40
|
+
Position.status[s] = s
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
module.exports = Position
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Model = require('../model')
|
|
4
|
+
|
|
5
|
+
class Tick extends Model {
|
|
6
|
+
serialize () {
|
|
7
|
+
if (!this.symbol) return []
|
|
8
|
+
|
|
9
|
+
if (this.symbol[0] === 't') {
|
|
10
|
+
return [
|
|
11
|
+
this.symbol,
|
|
12
|
+
this.bid,
|
|
13
|
+
this.bidSize,
|
|
14
|
+
this.ask,
|
|
15
|
+
this.askSize,
|
|
16
|
+
this.dailyChange,
|
|
17
|
+
this.dailyChangePerc,
|
|
18
|
+
this.lastPrice,
|
|
19
|
+
this.volume,
|
|
20
|
+
this.high,
|
|
21
|
+
this.low
|
|
22
|
+
]
|
|
23
|
+
} else {
|
|
24
|
+
return [
|
|
25
|
+
this.symbol,
|
|
26
|
+
this.frr,
|
|
27
|
+
this.bid,
|
|
28
|
+
this.bidSize,
|
|
29
|
+
this.bidPeriod,
|
|
30
|
+
this.ask,
|
|
31
|
+
this.askSize,
|
|
32
|
+
this.askPeriod,
|
|
33
|
+
this.dailyChange,
|
|
34
|
+
this.dailyChangePerc,
|
|
35
|
+
this.lastPrice,
|
|
36
|
+
this.volume,
|
|
37
|
+
this.high,
|
|
38
|
+
this.low
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static unserialize (arr) {
|
|
44
|
+
if (Array.isArray(arr[0])) {
|
|
45
|
+
return arr.map(tick => Tick.unserialize(tick))
|
|
46
|
+
} else if (!arr[0]) { // no symbol
|
|
47
|
+
return null
|
|
48
|
+
} else if (arr[0][0] === 't') {
|
|
49
|
+
return {
|
|
50
|
+
symbol: arr[0],
|
|
51
|
+
bid: arr[1],
|
|
52
|
+
bidSize: arr[2],
|
|
53
|
+
ask: arr[3],
|
|
54
|
+
askSize: arr[4],
|
|
55
|
+
dailyChange: arr[5],
|
|
56
|
+
dailyChangePerc: arr[6],
|
|
57
|
+
lastPrice: arr[7],
|
|
58
|
+
volume: arr[8],
|
|
59
|
+
high: arr[9],
|
|
60
|
+
low: arr[10]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
symbol: arr[0],
|
|
66
|
+
frr: arr[1],
|
|
67
|
+
bid: arr[2],
|
|
68
|
+
bidSize: arr[3],
|
|
69
|
+
bidPeriod: arr[4],
|
|
70
|
+
ask: arr[5],
|
|
71
|
+
askSize: arr[6],
|
|
72
|
+
askPeriod: arr[7],
|
|
73
|
+
dailyChange: arr[8],
|
|
74
|
+
dailyChangePerc: arr[9],
|
|
75
|
+
lastPrice: arr[10],
|
|
76
|
+
volume: arr[11],
|
|
77
|
+
high: arr[12],
|
|
78
|
+
low: arr[13]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = Tick
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Model = require('../model')
|
|
4
|
+
|
|
5
|
+
class Trade extends Model {
|
|
6
|
+
serialize () {
|
|
7
|
+
return [
|
|
8
|
+
this.id,
|
|
9
|
+
this.pair,
|
|
10
|
+
this.mtsCreate,
|
|
11
|
+
this.orderID,
|
|
12
|
+
this.execAmount,
|
|
13
|
+
this.execPrice,
|
|
14
|
+
this.orderType,
|
|
15
|
+
this.orderPrice,
|
|
16
|
+
this.maker ? 1 : 0,
|
|
17
|
+
this.fee,
|
|
18
|
+
this.feeCurrency
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static unserialize (arr) {
|
|
23
|
+
if (Array.isArray(arr[0])) {
|
|
24
|
+
return arr.map(trade => Trade.unserialize(trade))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
id: arr[0],
|
|
29
|
+
pair: arr[1],
|
|
30
|
+
mtsCreate: arr[2],
|
|
31
|
+
orderID: arr[3],
|
|
32
|
+
execAmount: arr[4],
|
|
33
|
+
execPrice: arr[5],
|
|
34
|
+
orderType: arr[6],
|
|
35
|
+
orderPrice: arr[7],
|
|
36
|
+
maker: arr[8] === 1,
|
|
37
|
+
fee: arr[9],
|
|
38
|
+
feeCurrency: arr[10]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = Trade
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Model = require('../model')
|
|
4
|
+
|
|
5
|
+
class TradeTick extends Model {
|
|
6
|
+
serialize () {
|
|
7
|
+
return [
|
|
8
|
+
this.id,
|
|
9
|
+
this.mts,
|
|
10
|
+
this.amount,
|
|
11
|
+
this.price
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static unserialize (arr) {
|
|
16
|
+
if (Array.isArray(arr[0])) {
|
|
17
|
+
return arr.map(trade => TradeTick.unserialize(trade))
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
id: arr[0],
|
|
22
|
+
mts: arr[1],
|
|
23
|
+
amount: arr[2],
|
|
24
|
+
price: arr[3]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = TradeTick
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Model = require('../model')
|
|
4
|
+
|
|
5
|
+
class Wallet extends Model {
|
|
6
|
+
serialize () {
|
|
7
|
+
return [
|
|
8
|
+
this.type,
|
|
9
|
+
this.currency,
|
|
10
|
+
this.balance,
|
|
11
|
+
this.unsettledInterest,
|
|
12
|
+
this.balanceAvailable
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static unserialize (arr) {
|
|
17
|
+
return {
|
|
18
|
+
type: arr[0],
|
|
19
|
+
currency: arr[1],
|
|
20
|
+
balance: arr[2],
|
|
21
|
+
unsettledInterest: arr[3],
|
|
22
|
+
balanceAvailable: arr[4]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Wallet.type = {}
|
|
28
|
+
const types = ['exchange', 'margin', 'funding']
|
|
29
|
+
|
|
30
|
+
types.forEach((t) => {
|
|
31
|
+
Wallet.type[t.toUpperCase()] = t
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
module.exports = Wallet
|