@icgio/icg-exchanges-wrapper 1.8.6

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.
@@ -0,0 +1,1024 @@
1
+ const _ = require('lodash')
2
+
3
+ const uuidv4 = require('uuid/v4')
4
+ const Influx = require('influx')
5
+
6
+ const icg_exchanges = require('@icgio/icg-exchanges')
7
+ const utils = require('@icgio/icg-utils').utils
8
+ const get_coinmarketcap_rates = require('@icgio/icg-utils').coinmarketcap
9
+
10
+ const { round_price, round_amount } = require('@icgio/icg-exchanges-data')
11
+
12
+ const Account = require('./account.js')
13
+
14
+ const limits = {
15
+ public_max_concurrent: 10,
16
+ public_interval_concurrent: 1000,
17
+ private_max_concurrent: 5,
18
+ private_interval_concurrent: 1000
19
+ }
20
+ const small_limits = {
21
+ public_max_concurrent: 5,
22
+ public_interval_concurrent: 1000,
23
+ private_max_concurrent: 3,
24
+ private_interval_concurrent: 1000
25
+ }
26
+ const mimimum_limits = {
27
+ public_max_concurrent: 2,
28
+ public_interval_concurrent: 1000,
29
+ private_max_concurrent: 1,
30
+ private_interval_concurrent: 3000
31
+ }
32
+
33
+ const rates_length = 10
34
+
35
+ module.exports = class Orders {
36
+ constructor (exchange_basecur_curs, cd, settings) {
37
+ this.exchange_basecur_curs = exchange_basecur_curs
38
+ let { exchange_pairs, exchange_curs, pair_exchanges } = utils.exchange_basecur_curs_converter(exchange_basecur_curs)
39
+ this.exchange_pairs = exchange_pairs
40
+ this.pair_exchanges = pair_exchanges
41
+ this.Exchanges = {}
42
+ this.settings = settings || {}
43
+ this.ws_enabled = settings.ws_enabled || false
44
+ this.interval_dict = settings.interval_dict || {}
45
+ this.influx_url_check_volume = settings.influx_url_check_volume
46
+ this.check_init_order_opened = settings.check_init_order_opened || true
47
+ this.check_init_order_opened_timeout = settings.check_init_order_opened_timeout || 5 * 1000
48
+ this.cancel_previous_orders = settings.cancel_previous_orders || false
49
+ this.cancel_range_orders = settings.cancel_range_orders || false
50
+ this.delete_finished_orders_timeout = settings.delete_finished_orders_timeout || 30 * 1000 // CANCELED or F-FILLED
51
+ this.interval_dict = settings.interval_dict || {}
52
+ this.major_exchanges = settings.major_exchanges || []
53
+ this.no_cancel_range_exchanges = settings.no_cancel_range_exchanges || []
54
+ this.no_trades_function_exchanges = settings.no_trades_function_exchanges || []
55
+ this.no_trades_function_f_filled_timeout = settings.no_trades_function_f_filled_timeout || 30 * 1000
56
+ this.bad_trades_function_exchanges = settings.bad_trades_function_exchanges || []
57
+ this.buy_sell_limits_threshold = settings.buy_sell_limits_threshold || 0.95
58
+ this.p_filled_threshold = settings.p_filled_threshold || 0
59
+ this.f_filled_threshold = settings.f_filled_threshold || 0.95
60
+ this.previous_orders_canceled = false
61
+ this.previous_orders_canceled_exchange_pair = {}
62
+ this.init_account_from_first_balances = settings.init_account_from_first_balances || true
63
+ this.account_init = false
64
+ for (let exchange in exchange_pairs) {
65
+ if (exchange === 'bitfinex') {
66
+ this.Exchanges[exchange] = new icg_exchanges[_.upperFirst(exchange)](cd[exchange]['api_keys'], cd[exchange]['secret_keys'], _.assign(small_limits, cd[exchange]))
67
+ } else if (exchange === 'okex' || exchange === 'bgogo') {
68
+ this.Exchanges[exchange] = new icg_exchanges[_.upperFirst(exchange)](cd[exchange]['api_key'], cd[exchange]['secret_key'], _.assign(small_limits, cd[exchange]))
69
+ } else if (exchange === 'bitforex' || exchange === 'bitkub' || exchange === 'coinbene') {
70
+ this.Exchanges[exchange] = new icg_exchanges[_.upperFirst(exchange)](cd[exchange]['api_key'], cd[exchange]['secret_key'], _.assign(mimimum_limits, cd[exchange]))
71
+ } else if (cd[exchange]['api_keys'] || exchange === 'kucoin') {
72
+ this.Exchanges[exchange] = new icg_exchanges[_.upperFirst(exchange)](cd[exchange]['api_keys'], cd[exchange]['secret_keys'], _.assign(small_limits, cd[exchange]))
73
+ } else if (cd[exchange]['api_keys']) {
74
+ this.Exchanges[exchange] = new icg_exchanges[_.upperFirst(exchange)](cd[exchange]['api_keys'], cd[exchange]['secret_keys'], _.assign(limits, cd[exchange]))
75
+ } else {
76
+ this.Exchanges[exchange] = new icg_exchanges[_.upperFirst(exchange)](cd[exchange]['api_key'], cd[exchange]['secret_key'], _.assign(limits, cd[exchange]))
77
+ }
78
+ if (!this.interval_dict || !this.interval_dict[exchange]) {
79
+ this.interval_dict[exchange] = {
80
+ 'balances': 10 * 1000,
81
+ 'positions': 10 * 1000,
82
+ 'open_orders': 10 * 1000,
83
+ 'trades': 10 * 1000,
84
+ 'rates': 1 * 1000,
85
+ 'market_history': 2 * 1000,
86
+ }
87
+ } else {
88
+ this.interval_dict[exchange].balances = this.interval_dict[exchange].balances || 10 * 1000
89
+ this.interval_dict[exchange].positions = this.interval_dict[exchange].positions || 10 * 1000
90
+ this.interval_dict[exchange].open_orders = this.interval_dict[exchange].open_orders || 10 * 1000
91
+ this.interval_dict[exchange].trades = this.interval_dict[exchange].trades || 10 * 1000
92
+ this.interval_dict[exchange].rates = this.interval_dict[exchange].rates || 1 * 1000
93
+ this.interval_dict[exchange].market_history = this.interval_dict[exchange].market_history || 2 * 1000
94
+ }
95
+ }
96
+ this.balances = {}, this.open_orders = {}, this.trades = {}, this.rates = {}, this.market_history = {}, this.volumes = {}, this.cmc_rates = {}
97
+ this.rates_combined_all = {}, this.rates_combined_all_with_buy_sell_limits = {}, this.rates_combined_major = {}, this.rates_combined_good_with_buy_sell_limits = {}
98
+ this.buy_sell_limits = {}
99
+ this.order_info = {}
100
+ this.order_info_status = {}
101
+ this.enabled = settings.enabled || {
102
+ 'info_log': true,
103
+ 'error_log': true,
104
+ 'balances_check': true,
105
+ 'positions_check': false,
106
+ 'open_orders_check': true,
107
+ 'trades_check': true,
108
+ 'rates_check': true,
109
+ 'market_history_check': true,
110
+ 'volumes_check': false,
111
+ 'cmc_rates_check': true
112
+ }
113
+ this.info_log = (...args) => {
114
+ if (this.enabled.info_log)
115
+ console.log(...args)
116
+ }
117
+ this.error_log = (...args) => {
118
+ if (this.enabled.info_log)
119
+ console.error(...args)
120
+ }
121
+ if (this.enabled.balances_check) {
122
+ this.check_balances()
123
+ }
124
+ if (this.enabled.positions_check) {
125
+ this.check_positions()
126
+ }
127
+ if (this.enabled.open_orders_check) {
128
+ this.check_open_orders()
129
+ }
130
+ if (this.enabled.trades_check) {
131
+ this.trades_amount_past_hour = {}
132
+ this.check_trades()
133
+ }
134
+ if (this.enabled.rates_check) {
135
+ this.check_rates()
136
+ }
137
+ if (this.enabled.market_history_check) {
138
+ this.check_market_history()
139
+ }
140
+ if (this.enabled.volumes_check) {
141
+ this.check_volumes()
142
+ }
143
+ if (this.enabled.cmc_rates_check) {
144
+ this.check_cmc_rates()
145
+ }
146
+ if (this.enabled.balances_check && this.enabled.open_orders_check && this.enabled.trades_check) {
147
+ setInterval(() => {
148
+ this.process_bot(this.balances, this.open_orders, this.trades)
149
+ }, 1000)
150
+ }
151
+ this.ws_market_first_time = {}
152
+ }
153
+ init_account (initial_balances) {
154
+ this.account = new Account(initial_balances)
155
+ }
156
+ set_exchange_assets_from_balances (balances) {
157
+ this.account.set_exchange_assets_from_balances(balances)
158
+ }
159
+ limit_trade (exchange, pair, method, price, amount, id=uuidv4().slice(0, 13), order_type='', limiter_on=true) {
160
+ price = round_price(_.upperFirst(exchange), pair, price)
161
+ amount = round_amount(_.upperFirst(exchange), pair, amount)
162
+ this.info_log('%s %s %s %s %s %s at %s', limiter_on, order_type, exchange, pair, method, amount, price)
163
+ this.update_order_info(exchange, pair, method, id, {
164
+ order_type,
165
+ status: 'INIT',
166
+ id,
167
+ order_id: id,
168
+ type: method,
169
+ price,
170
+ amount,
171
+ f_amount: 0,
172
+ f_percentage: 0,
173
+ t_amount: amount,
174
+ open_time: new Date(),
175
+ close_time: null
176
+ }, order_type + ' init')
177
+ let no_callback_timeout = setTimeout(() => {
178
+ if (_.get(this.order_info, [exchange, pair, method, id, 'status']) === 'INIT') {
179
+ console.log('no callback: %s %s %s %s %s', exchange, pair, method, id, order_type)
180
+ this.update_order_info(exchange, pair, method, id, {
181
+ status: 'N-OPENED-TIMEOUT'
182
+ }, order_type + ' n-opened-timeout-init')
183
+ }
184
+ }, 60 * 1000)
185
+ let limit_trade = (cb) => {
186
+ if (limiter_on) {
187
+ this.Exchanges[exchange].limit_trade(pair, method, price, amount, cb)
188
+ } else {
189
+ this.Exchanges[exchange].limit_trade_base(pair, method, price, amount, cb)
190
+ }
191
+ }
192
+ limit_trade((res) => {
193
+ if (res.success) {
194
+ let order_id = res.body
195
+ this.delete_order_info(exchange, pair, method, id, 'limit-trade-success')
196
+ this.update_order_info(exchange, pair, method, order_id, {
197
+ order_type,
198
+ status: 'N-FILLED',
199
+ id,
200
+ order_id,
201
+ type: method,
202
+ price,
203
+ amount,
204
+ f_amount: 0,
205
+ f_percentage: 0,
206
+ t_amount: amount,
207
+ open_time: new Date(),
208
+ close_time: null
209
+ }, order_type + ' n-filled')
210
+ } else if (res.error === 'amount-too-small' || res.error === 'insufficient-funds') {
211
+ this.delete_order_info(exchange, pair, method, id, 'limit-trade-' + res.error)
212
+ } else {
213
+ if (order_type.startsWith('self') || order_type.startsWith('maker_2')) {
214
+ this.delete_order_info(exchange, pair, method, id, 'limit-trade-timeout-' + order_type)
215
+ }
216
+ // else if (_.get(this.order_info, [exchange, pair, method, id, 'status']) === 'INIT') { // make sure no_callback_timeout is NOT running zero
217
+ // this.update_order_info(exchange, pair, method, id, {
218
+ // status: 'N-OPENED-TIMEOUT'
219
+ // }, order_type + ' n-opened-timeout-callback')
220
+ // }
221
+ this.error_log('limit trade error: %s %s %s %s %s %s %s %j', order_type, id, exchange, pair, method, price, amount, res)
222
+ }
223
+ clearTimeout(no_callback_timeout)
224
+ })
225
+ }
226
+ limit_trade_all (pair, method, price, total) {
227
+ if (!this.volumes[pair]) {
228
+ this.error_log('%s volumes do not exist')
229
+ return
230
+ }
231
+ let id = uuidv4().slice(0, 13)
232
+ let sum = _.sum(_.values(this.volumes[pair]))
233
+ for (let exchange of this.pair_exchanges[pair]) {
234
+ let amount = this.volumes[pair][exchange] / sum * total
235
+ this.limit_trade(exchange, pair, method, price, amount, id)
236
+ }
237
+ }
238
+ market_trade (exchange, pair, method, amount, id=uuidv4().slice(0, 13)) {
239
+ if (!this.rates[exchange][pair]) {
240
+ this.info_log('%s %s rates do not exist', exchange, pair)
241
+ return
242
+ }
243
+ let input_array = (method === 'sell') ? this.rates[exchange][pair].bids : this.rates[exchange][pair].asks
244
+ let { price } = utils.vol_position(input_array, amount)
245
+ this.limit_trade(exchange, pair, method, price, amount, id)
246
+ }
247
+ market_trade_all (pair, method, total) {
248
+ if (!this.rates_combined_all[pair]) {
249
+ this.error_log('%s rates combined do not exist', pair)
250
+ return
251
+ }
252
+ let type = method === 'buy' ? 'asks' : 'bids' // reverse because it is market order
253
+ let { price_exchange, vol_exchange } = utils.vol_position_combined(this.rates_combined_all[pair][type], total)
254
+ let id = uuidv4().slice(0, 13)
255
+ for (let exchange of this.pair_exchanges[pair]) {
256
+ if (price_exchange[exchange] && vol_exchange[exchange])
257
+ this.limit_trade(exchange, pair, method, price_exchange[exchange], vol_exchange[exchange], id)
258
+ }
259
+ }
260
+ cancel_order (exchange, pair, order) {
261
+ let original_status = order.status
262
+ this.update_order_info(exchange, pair, order.type, order.order_id, {
263
+ status: 'CANCELING'
264
+ }, order.order_type + ' canceling')
265
+ order.exchange = exchange, order.pair = pair
266
+ this.Exchanges[exchange].cancel_order_by_order(order, (res) => {
267
+ if (res.success || (!res.success && res.error === 'order-not-open' && original_status === 'CANCELING')) {
268
+ this.update_order_info(exchange, pair, order.type, order.order_id, {
269
+ status: 'CANCELED',
270
+ close_time: new Date()
271
+ }, order.order_type + ' canceled')
272
+ setTimeout(() => {
273
+ this.delete_order_info(exchange, pair, order.type, order.order_id, 'cancel-order-success')
274
+ }, this.delete_finished_orders_timeout)
275
+ } else if (!res.success && res.error === 'order-not-open' && original_status !== 'CANCELED') {
276
+ // this.info_log('%s ORDER CANNOT BE CANCELED: %j', original_status, order)
277
+ this.update_order_info(exchange, pair, order.type, order.order_id, {
278
+ status: 'F-FILLED',
279
+ amount: 0,
280
+ f_amount: order.amount,
281
+ f_percentage: 1,
282
+ close_time: new Date()
283
+ }, order.order_type + ' cannot-be-canceled')
284
+ setTimeout(() => {
285
+ this.delete_order_info(exchange, pair, order.type, order.order_id, 'cannot-be-canceled')
286
+ }, this.delete_finished_orders_timeout)
287
+ } else {
288
+ console.error('cancel order:', exchange, pair, order, res)
289
+ }
290
+ })
291
+ }
292
+ get_order_info_all () {
293
+ return this.order_info
294
+ }
295
+ get_order_info_all_stats () {
296
+ let info_all = this.get_order_info_all(), info_all_stats = {}
297
+ for (let exchange in info_all) {
298
+ for (let pair in info_all[exchange]) {
299
+ for (let type in info_all[exchange][pair]) {
300
+ _.set(info_all_stats, [exchange, pair, type], _.keys(info_all[exchange][pair][type]).length)
301
+ }
302
+ }
303
+ }
304
+ return info_all_stats
305
+ }
306
+ get_order_info_by_order_type (order_type) {
307
+ let order_info_temp = {}
308
+ for (let exchange in this.order_info) {
309
+ for (let pair in this.order_info[exchange]) {
310
+ for (let type in this.order_info[exchange][pair]) {
311
+ for (let order_id in this.order_info[exchange][pair][type]) {
312
+ if (_.get(this.order_info, [exchange, pair, type, order_id, 'order_type']) === order_type) {
313
+ _.setWith(order_info_temp, `${exchange}.${pair}.${type}.${order_id}`, _.get(this.order_info, `${exchange}.${pair}.${type}.${order_id}`), Object)
314
+ }
315
+ }
316
+ }
317
+ }
318
+ }
319
+ return order_info_temp
320
+ }
321
+ get_order_info_status_all (exchange, pair, type, status) {
322
+ if (type === 'both') {
323
+ return this.get_order_info_status_all(exchange, pair, 'sell', status).concat(this.get_order_info_status_all(exchange, pair, 'buy', status))
324
+ }
325
+ _.set(this.order_info_status, [exchange, pair, type, status], [])
326
+ for (let order_id in _.get(this.order_info, [exchange, pair, type], {})) {
327
+ let order_status = _.get(this.order_info, [exchange, pair, type, order_id, 'status'])
328
+ if (order_status === status || status.indexOf(order_status) > -1) {
329
+ this.order_info_status[exchange][pair][type][status].push(this.order_info[exchange][pair][type][order_id])
330
+ }
331
+ }
332
+ return this.order_info_status[exchange][pair][type][status]
333
+ }
334
+ get_order_info_status_by_order_type (exchange, pair, type, status, order_type) {
335
+ return this.get_order_info_status_all(exchange, pair, type, status).filter(o => o.order_type === order_type)
336
+ }
337
+ process_bot (balances, open_orders, trades) {
338
+ for (let exchange in trades) {
339
+ for (let pair in trades[exchange]) {
340
+ trades[exchange][pair].trades.map(trade => {
341
+ if (_.get(this.order_info, [exchange, pair, trade.type, trade.order_id])) {
342
+ let order_info = this.order_info[exchange][pair][trade.type][trade.order_id]
343
+ if (order_info.status === 'CANCELED' || order_info.status === 'CANCELING') {
344
+ let type = trade.type, order_id = trade.order_id
345
+ // this.info_log('TRADES: %s ORDER FILLED', order_info.status, trade, order_info)
346
+ this.update_order_info(exchange, pair, type, order_id, {
347
+ status: 'F-FILLED',
348
+ price: trade.price,
349
+ amount: 0,
350
+ f_amount: trade.amount,
351
+ t_amount: trade.amount,
352
+ f_percentage: 1,
353
+ close_time: trade.close_time || new Date()
354
+ }, order_info.order_type + ' canceled-order-filled')
355
+ setTimeout(() => {
356
+ this.delete_order_info(exchange, pair, type, order_id, 'canceled-order-filled')
357
+ }, this.delete_finished_orders_timeout)
358
+ } else if (order_info.status === 'F-FILLED' && trade.amount > order_info.f_amount) {
359
+ // this.info_log('TRADES: FILLED ORDER FILLED MORE', trade, order_info)
360
+ this.update_order_info(exchange, pair, order_info.type, order_info.order_id, {
361
+ f_amount: trade.amount,
362
+ t_amount: trade.amount,
363
+ f_percentage: 1
364
+ }, order_info.order_type + ' filled-order-filled-more')
365
+ } else if (_.includes(['N-FILLED', 'P-FILLED'], order_info.status) && trade.amount > order_info.f_amount && trade.amount / order_info.t_amount > this.f_filled_threshold) {
366
+ // this.info_log('TRADES: %s %s ORDER F-FILLED', exchange, pair, trade)
367
+ this.update_order_info(exchange, pair, order_info.type, order_info.order_id, {
368
+ status: 'F-FILLED',
369
+ price: trade.price,
370
+ amount: order_info.t_amount - trade.amount,
371
+ f_amount: trade.amount,
372
+ f_percentage: trade.amount / order_info.t_amount,
373
+ close_time: trade.close_time || new Date()
374
+ }, order_info.order_type + ' order-f-filled-1')
375
+ setTimeout(() => {
376
+ this.delete_order_info(exchange, pair, order_info.type, order_info.order_id, 'f-filled-trades')
377
+ }, this.delete_finished_orders_timeout)
378
+ } else if (_.includes(['N-FILLED', 'P-FILLED'], order_info.status) && trade.amount > order_info.f_amount && trade.amount / order_info.t_amount > this.p_filled_threshold) {
379
+ // this.info_log('TRADES: %s %s ORDER P-FILLED', exchange, pair, trade)
380
+ this.update_order_info(exchange, pair, order_info.type, order_info.order_id, {
381
+ status: 'P-FILLED',
382
+ amount: order_info.t_amount - trade.amount,
383
+ f_amount: trade.amount,
384
+ f_percentage: trade.amount / order_info.t_amount
385
+ }, order_info.order_type + ' order-p-filled-1')
386
+ } else if (_.includes(['F-FILLED', 'P-FILLED'], order_info.status)) {
387
+
388
+ } else {
389
+ this.info_log('TRADES: UNKNOWN %j', trade, this.order_info[exchange][pair])
390
+ }
391
+ }
392
+ })
393
+ }
394
+ }
395
+ for (let exchange of this.no_trades_function_exchanges) {
396
+ for (let pair in _.get(this.order_info, [exchange], {})) {
397
+ for (let type in _.get(this.order_info, [exchange, pair], {})) {
398
+ for (let order_id in _.get(this.order_info, [exchange, pair, type], {})) {
399
+ let order_info_order = this.order_info[exchange][pair][type][order_id]
400
+ if ((order_info_order.status === 'N-FILLED' || order_info_order.status === 'P-FILLED') && order_info_order.open_time < new Date() - this.no_trades_function_f_filled_timeout) {
401
+ let exist = false
402
+ open_orders[exchange][pair].open_orders.map(o => {
403
+ if (o.order_id === order_info_order.order_id) {
404
+ exist = true
405
+ }
406
+ })
407
+ if (!exist) {
408
+ // this.info_log('ORDERS: %s %s ORDER F-FILLED NO TRADES FUNCTION EXCHANGES', exchange, pair)
409
+ this.update_order_info(exchange, pair, order_info_order.type, order_info_order.order_id, {
410
+ status: 'F-FILLED',
411
+ amount: 0,
412
+ f_amount: order_info_order.t_amount,
413
+ f_percentage: 1,
414
+ close_time: new Date()
415
+ }, order_info_order.order_type + ' order-f-filled-2')
416
+ setTimeout(() => {
417
+ this.delete_order_info(exchange, pair, order_info_order.type, order_info_order.order_id, 'f-filled-no-trades-function')
418
+ }, this.delete_finished_orders_timeout)
419
+ }
420
+ }
421
+ }
422
+ }
423
+ }
424
+ }
425
+ for (let exchange in open_orders) {
426
+ for (let pair in open_orders[exchange]) {
427
+ open_orders[exchange][pair].open_orders.map(order => {
428
+ if (_.get(this.order_info, [exchange, pair, order.type, order.order_id])) {
429
+ let order_info = this.order_info[exchange][pair][order.type][order.order_id]
430
+ if (_.includes(['N-FILLED', 'P-FILLED'], order_info.status) && order.f_amount > order_info.f_amount && order.f_amount / order_info.t_amount > this.f_filled_threshold) {
431
+ // this.info_log('ORDERS: %s %s ORDER F-FILLED', exchange, pair)
432
+ this.update_order_info(exchange, pair, order_info.type, order_info.order_id, {
433
+ status: 'F-FILLED',
434
+ amount: order.amount,
435
+ f_amount: order.f_amount,
436
+ f_percentage: order.f_amount / order_info.t_amount,
437
+ close_time: order.close_time || new Date()
438
+ }, order_info.order_type + ' order-f-filled-3')
439
+ setTimeout(() => {
440
+ this.delete_order_info(exchange, pair, order_info.type, order_info.order_id, 'f-filled-open-orders')
441
+ }, this.delete_finished_orders_timeout)
442
+ } else if (_.includes(['N-FILLED', 'P-FILLED'], order_info.status) && order.f_amount > order_info.f_amount && order.f_amount / order_info.t_amount > this.p_filled_threshold) {
443
+ // this.info_log('ORDERS: %s %s ORDER P-FILLED', exchange, pair)
444
+ this.update_order_info(exchange, pair, order_info.type, order_info.order_id, {
445
+ status: 'P-FILLED',
446
+ amount: order.amount,
447
+ f_amount: order.f_amount,
448
+ f_percentage: order.f_amount / order_info.t_amount
449
+ }, order_info.order_type + ' order-p-filled-2')
450
+ }
451
+ } else if (this.get_order_info_status_all(exchange, pair, 'both', 'INIT') && this.check_init_order_opened) {
452
+ this.get_order_info_status_all(exchange, pair, 'both', 'INIT').map(init_order => {
453
+ let init_order_price = round_price(exchange, pair, init_order.price)
454
+ let order_price = round_price(exchange, pair, order.price)
455
+ let init_order_time = init_order.open_time.getTime()
456
+ let order_time = order.open_time.getTime()
457
+ if (init_order.type === order.type && init_order_price === order_price && order_time - init_order_time > 0 && order_time - init_order_time < this.check_init_order_opened_timeout) {
458
+ // this.info_log('ORDERS: %s %s %s %s INIT ORDER OPENED', init_order.order_id, order.order_id, exchange, pair)
459
+ this.delete_order_info(exchange, pair, init_order.type, init_order.order_id, 'init-order-opened')
460
+ this.update_order_info(exchange, pair, order.type, order.order_id, {
461
+ status: 'N-FILLED',
462
+ order_id: order.order_id,
463
+ type: order.type,
464
+ price: order.price,
465
+ amount: order.amount,
466
+ f_amount: 0,
467
+ t_amount: order.amount,
468
+ open_time: order.open_time || new Date(),
469
+ close_time: null
470
+ }, init_order.order_type + ' init-order-opened')
471
+ }
472
+ })
473
+ }
474
+ })
475
+ }
476
+ }
477
+ }
478
+ update_order_info (exchange, pair, type, order_id, dict, note) {
479
+ if (!order_id) {
480
+ this.error_log('UPDATE %s: order_id invalid %s %s %s %s %j', note, exchange, pair, type, order_id, dict)
481
+ return
482
+ }
483
+ for (let key in dict) {
484
+ if (key === 'f_percentage') {
485
+ dict[key] = Math.round(dict[key] * 100) / 100
486
+ }
487
+ _.setWith(this.order_info, `${exchange}.${pair}.${type}.${order_id}.${key}`, dict[key], Object)
488
+ }
489
+ this.info_log('UPDATE %s: %s %s %s %s %j', note, exchange, pair, type, order_id, dict)
490
+ }
491
+ delete_order_info (exchange, pair, type, order_id, note) {
492
+ this.order_info[exchange][pair][type] = _.omit(this.order_info[exchange][pair][type], [order_id])
493
+ this.info_log('DELETE %s: %s %s %s %s', note, exchange, pair, type, order_id)
494
+ }
495
+ check_balances () {
496
+ let balances_handler = (exchange, res) => {
497
+ if (res.success) {
498
+ _.set(this.balances, [exchange], Object.assign(res.body, { update_time: new Date() }))
499
+ for (let exchange in this.exchange_basecur_curs) {
500
+ for (let base_cur in this.exchange_basecur_curs[exchange]) {
501
+ this.exchange_basecur_curs[exchange][base_cur].map(cur => {
502
+ let cur_balance = _.get(this.balances, [exchange, 'available', cur], 0)
503
+ let base_cur_balance = _.get(this.balances, [exchange, 'available', base_cur], 0)
504
+ let pair = cur + base_cur
505
+ _.set(this.buy_sell_limits, [exchange, pair], {
506
+ sell: cur_balance * this.buy_sell_limits_threshold,
507
+ buy: base_cur_balance * this.buy_sell_limits_threshold
508
+ })
509
+ })
510
+ }
511
+ }
512
+ if (!this.account_init && _.keys(this.balances).length === _.keys(this.exchange_pairs).length) {
513
+ this.account_init = true
514
+ this.init_account(this.balances)
515
+ }
516
+ } else if (_.get(this.balances, [exchange, 'update_time']) < new Date() - this.interval_dict[exchange].balances) {
517
+ this.error_log('%s balances expired: %j', exchange, res)
518
+ this.balances = _.omit(this.balances, [exchange])
519
+ this.buy_sell_limits = _.omit(this.buy_sell_limits, [exchange])
520
+ }
521
+ }
522
+ function get_balances (Exchanges, interval_dict) {
523
+ for (let exchange in Exchanges) {
524
+ if (Exchanges[exchange].balance_ws) {
525
+ setInterval(() => {
526
+ if (Exchanges[exchange].ws_status().trading === 'n-opened')
527
+ Exchanges[exchange].ws_account()
528
+ Exchanges[exchange].balance_ws((res) => { balances_handler (exchange, res) })
529
+ }, interval_dict[exchange].balances)
530
+ } else {
531
+ setInterval(() => {
532
+ Exchanges[exchange].balance((res) => { balances_handler (exchange, res) })
533
+ }, interval_dict[exchange].balances)
534
+ }
535
+ }
536
+ }
537
+ get_balances(this.Exchanges, this.interval_dict)
538
+ }
539
+ check_positions () {
540
+ let position_handler = (exchange, pair, res) => {
541
+
542
+ }
543
+ let position_all_handler = (exchange, res) => {
544
+ if (res.success) {
545
+ _.set(this.positions, [exchange], Object.assign(res.body, { update_time: new Date() }))
546
+ for (let exchange in this.exchange_pairs) {
547
+ this.exchange_pairs[exchange].map(pair => {
548
+ _.set(this.buy_sell_limits, [exchange, pair], {
549
+ sell: 1000 + _.get(res.body, ['total', pair], 0),
550
+ buy: 1000 - _.get(res.body, ['total', pair], 0)
551
+ })
552
+ })
553
+ }
554
+ } else if (_.get(this.positions, [exchange, 'update_time']) < new Date() - this.interval_dict[exchange].positions) {
555
+ this.error_log('%s positions expired: %j', exchange, res)
556
+ this.positions = _.omit(this.positions, [exchange])
557
+ this.buy_sell_limits = _.omit(this.buy_sell_limits, [exchange])
558
+ }
559
+ }
560
+ function get_positions (Exchanges, interval_dict) {
561
+ for (let exchange in Exchanges) {
562
+ if (Exchanges[exchange].position_all_ws) {
563
+ if (Exchanges[exchange].ws_status().trading === 'n-opened')
564
+ Exchanges[exchange].ws_account()
565
+ setInterval(() => {
566
+ Exchanges[exchange].position_all_ws((res) => { position_all_handler (exchange, res) })
567
+ }, interval_dict[exchange].positions)
568
+ } else if (Exchanges[exchange].position_ws) {
569
+ if (Exchanges[exchange].ws_status().trading === 'n-opened')
570
+ Exchanges[exchange].ws_account()
571
+ setInterval(() => {
572
+ for (let pair of this.exchange_pairs[exchange]) {
573
+ Exchanges[exchange].position_ws(pair, (res) => { position_handler (exchange, pair, res) })
574
+ }
575
+ }, interval_dict[exchange].positions)
576
+ } else if (Exchanges[exchange].position_all) {
577
+ setInterval(() => {
578
+ Exchanges[exchange].position_all((res) => { position_all_handler (exchange, res) })
579
+ }, interval_dict[exchange].positions)
580
+ } else if (Exchanges[exchange].position) {
581
+ setInterval(() => {
582
+ for (let pair of this.exchange_pairs[exchange]) {
583
+ Exchanges[exchange].position_ws(pair, (res) => { position_handler (exchange, pair, res) })
584
+ }
585
+ }, interval_dict[exchange].positions)
586
+ }
587
+ }
588
+ }
589
+ get_positions(this.Exchanges, this.interval_dict)
590
+ }
591
+ check_open_orders () {
592
+ const open_orders_timeframe = 12 * 60 * 60 * 1000
593
+ let previous_orders_processer = (exchange, pair, orders) => {
594
+ if (this.cancel_previous_orders && !this.previous_orders_canceled) {
595
+ orders.map(order => {
596
+ this.info_log('cancel original order: %s %s %j', exchange, pair, order)
597
+ this.Exchanges[exchange].cancel_order_by_order(order, (res) => {})
598
+ })
599
+ if (orders.length === 0) {
600
+ _.set(this.previous_orders_canceled_exchange_pair, [exchange, pair], true)
601
+ }
602
+ if (!this.previous_orders_canceled) {
603
+ let previous_orders_canceled = true
604
+ for (let exchange in this.exchange_pairs) {
605
+ this.exchange_pairs[exchange].map(pair => {
606
+ if (!_.get(this.previous_orders_canceled_exchange_pair, [exchange, pair])) {
607
+ previous_orders_canceled = false
608
+ }
609
+ })
610
+ }
611
+ if (previous_orders_canceled)
612
+ this.info_log('original order canceled')
613
+ this.previous_orders_canceled = previous_orders_canceled
614
+ }
615
+ }
616
+ let rate_major = _.get(this.rates_combined_major, [pair])
617
+ if (this.cancel_range_orders && this.major_exchanges[pair].indexOf(exchange) === -1 && this.no_cancel_range_exchanges.indexOf(exchange) === -1 && rate_major) {
618
+ // console.log(exchange, pair, rate_major, orders)
619
+ orders.map(order => {
620
+ if (order.type === 'sell' && order.price < rate_major.asks[0][0] && order.order_status !== 'F-FILLED' && order.order_type !== 'arb') {
621
+ this.info_log('cancel range order: %s %s %j', exchange, pair, order)
622
+ order.order_type = 'range-order'
623
+ this.cancel_order(exchange, pair, order)
624
+ }
625
+ if (order.type === 'buy' && order.price > rate_major.bids[0][0] && order.order_status !== 'F-FILLED' && order.order_type !== 'arb') {
626
+ this.info_log('cancel range order: %s %s %j', exchange, pair, order)
627
+ order.order_type = 'range-order'
628
+ this.cancel_order(exchange, pair, order)
629
+ }
630
+ })
631
+ }
632
+ }
633
+ let open_orders_handler = (exchange, pair, res) => {
634
+ if (res.success) {
635
+ _.set(this.open_orders, [exchange, pair], { open_orders: res.body, update_time: new Date() })
636
+ previous_orders_processer(exchange, pair, res.body)
637
+ } else if (_.get(this.open_orders, [exchange, pair, 'update_time']) < new Date() - this.interval_dict[exchange].open_orders) {
638
+ this.error_log('%s %s open orders expired: %j', exchange, pair, res)
639
+ this.open_orders[exchange] = _.omit(this.open_orders[exchange], [pair])
640
+ } else if (res.error !== 'opening') {
641
+ this.error_log('%s %s open orders: %j', exchange, pair, res)
642
+ }
643
+ }
644
+ let all_open_orders_handler = (exchange, res) => {
645
+ if (res.success) {
646
+ for (let pair of this.exchange_pairs[exchange]) {
647
+ let open_orders = res.body.filter(o => o.pair === pair)
648
+ _.set(this.open_orders, [exchange, pair], { open_orders: open_orders, update_time: new Date() })
649
+ previous_orders_processer(exchange, pair, open_orders)
650
+ }
651
+ } else {
652
+ let error_logged = false
653
+ for (let pair of this.exchange_pairs[exchange]) {
654
+ if (_.get(this.open_orders, [exchange, pair, 'update_time']) < new Date() - this.interval_dict[exchange].open_orders) {
655
+ if (!error_logged) {
656
+ this.error_log('%s all open orders expired: %j', exchange, res)
657
+ error_logged = true
658
+ }
659
+ this.open_orders[exchange] = _.omit(this.open_orders[exchange], [pair])
660
+ } else if (res.error !== 'opening' && !error_logged) {
661
+ this.error_log('%s all open orders: %j', exchange, res)
662
+ error_logged = true
663
+ }
664
+ }
665
+ }
666
+ }
667
+ let get_open_orders_all = (Exchanges, exchange_pairs, interval_dict) => {
668
+ function get_all_open_orders_ws (exchange) {
669
+ if (Exchanges[exchange].ws_status().trading === 'n-opened')
670
+ Exchanges[exchange].ws_account()
671
+ Exchanges[exchange].get_all_open_orders_ws((res) => {
672
+ all_open_orders_handler(exchange, res)
673
+ setTimeout(() => {
674
+ get_all_open_orders_ws(exchange)
675
+ }, interval_dict[exchange].open_orders)
676
+ })
677
+ }
678
+ function get_open_orders_ws (exchange, pair) {
679
+ Exchanges[exchange].get_open_orders_ws(pair, (res) => {
680
+ open_orders_handler(exchange, pair, res)
681
+ setTimeout(() => {
682
+ get_open_orders_ws(exchange, pair)
683
+ }, interval_dict[exchange].open_orders)
684
+ })
685
+ }
686
+ function get_all_open_orders (exchange) {
687
+ Exchanges[exchange].get_all_open_orders((res) => {
688
+ all_open_orders_handler(exchange, res)
689
+ setTimeout(() => {
690
+ get_all_open_orders(exchange)
691
+ }, interval_dict[exchange].open_orders)
692
+ })
693
+ }
694
+ function get_open_orders (exchange, pair) {
695
+ Exchanges[exchange].get_open_orders(pair, (res) => {
696
+ open_orders_handler(exchange, pair, res)
697
+ setTimeout(() => {
698
+ get_open_orders(exchange, pair)
699
+ }, interval_dict[exchange].open_orders)
700
+ })
701
+ }
702
+ for (let exchange in Exchanges) {
703
+ if (Exchanges[exchange].get_all_open_orders_ws) {
704
+ if (Exchanges[exchange].ws_status().trading === 'n-opened')
705
+ Exchanges[exchange].ws_account()
706
+ get_all_open_orders_ws(exchange)
707
+ } else if (Exchanges[exchange].get_open_orders_ws) {
708
+ if (Exchanges[exchange].ws_status().trading === 'n-opened')
709
+ Exchanges[exchange].ws_account()
710
+ for (let pair of exchange_pairs[exchange]) {
711
+ get_open_orders_ws(exchange, pair)
712
+ }
713
+ } else if (Exchanges[exchange].get_all_open_orders) {
714
+ get_all_open_orders(exchange)
715
+ } else if (Exchanges[exchange].get_open_orders) {
716
+ for (let pair of exchange_pairs[exchange]) {
717
+ get_open_orders(exchange, pair)
718
+ }
719
+ }
720
+ }
721
+ }
722
+ get_open_orders_all(this.Exchanges, this.exchange_pairs, this.interval_dict)
723
+ }
724
+ check_trades () {
725
+ const trades_timeframe = 12 * 60 * 60 * 1000
726
+ let trades_handler = (exchange, pair, res) => {
727
+ if (res.success) {
728
+ _.set(this.trades, [exchange, pair], { trades: res.body, update_time: new Date() })
729
+ _.set(this.trades_amount_past_hour, [exchange, pair], _.sumBy(res.body.filter(t => t.close_time > new Date() - 60 * 60 * 1000 || t.open_time > new Date() - 60 * 60 * 1000), t => t.amount) || 0)
730
+ } else if (_.get(this.trades, [exchange, pair, 'update_time']) < new Date() - this.interval_dict[exchange].trades) {
731
+ this.error_log('%s %s trades expired: %j', exchange, pair, res)
732
+ this.trades[exchange] = _.omit(this.trades[exchange], [pair])
733
+ } else if (res.error !== 'opening') {
734
+ this.error_log('%s %s trades: %j', exchange, pair, res)
735
+ }
736
+ }
737
+ let all_trades_handler = (exchange, res) => {
738
+ if (res.success) {
739
+ for (let pair of this.exchange_pairs[exchange]) {
740
+ let trades = res.body.filter(o => o.pair === pair)
741
+ _.set(this.trades, [exchange, pair], { trades: trades, update_time: new Date() })
742
+ _.set(this.trades_amount_past_hour, [exchange, pair], _.sumBy(trades.filter(t => t.close_time > new Date() - 60 * 60 * 1000 || t.open_time > new Date() - 60 * 60 * 1000), t => t.amount) || 0)
743
+ }
744
+ } else if (res.error !== 'opening') {
745
+ let error_logged = false
746
+ for (let pair of this.exchange_pairs[exchange]) {
747
+ if (_.get(this.trades, [exchange, pair, 'update_time']) < new Date() - this.interval_dict[exchange].trades) {
748
+ if (!error_logged) {
749
+ this.error_log('%s all trades expired: %j', exchange, res)
750
+ error_logged = true
751
+ }
752
+ this.trades[exchange] = _.omit(this.trades[exchange], [pair])
753
+ } else if (res.error !== 'opening' && !error_logged) {
754
+ this.error_log('%s all trades: %j', exchange, res)
755
+ error_logged = true
756
+ }
757
+ }
758
+ }
759
+ }
760
+ let get_trades_all = (Exchanges, exchange_pairs, interval_dict) => {
761
+ let get_all_trades_ws = (exchange) => {
762
+ if (Exchanges[exchange].ws_status().trading === 'n-opened')
763
+ Exchanges[exchange].ws_account()
764
+ Exchanges[exchange].get_all_trades_ws(trades_timeframe, (res) => {
765
+ all_trades_handler(exchange, res)
766
+ setTimeout(() => {
767
+ get_all_trades_ws(exchange)
768
+ }, interval_dict[exchange].trades)
769
+ })
770
+ }
771
+ let get_trades_ws = (exchange, pair) => {
772
+ Exchanges[exchange].get_trades_ws(pair, trades_timeframe, (res) => {
773
+ trades_handler(exchange, pair, res)
774
+ setTimeout(() => {
775
+ get_trades_ws(exchange, pair)
776
+ }, interval_dict[exchange].trades)
777
+ })
778
+ }
779
+ let get_all_trades = (exchange) => {
780
+ Exchanges[exchange].get_all_trades(trades_timeframe, (res) => {
781
+ all_trades_handler(exchange, res)
782
+ setTimeout(() => {
783
+ get_all_trades(exchange)
784
+ }, interval_dict[exchange].trades)
785
+ })
786
+ }
787
+ let get_trades = (exchange, pair) => {
788
+ Exchanges[exchange].get_trades(pair, trades_timeframe, (res) => {
789
+ trades_handler(exchange, pair, res)
790
+ setTimeout(() => {
791
+ get_trades(exchange, pair)
792
+ }, interval_dict[exchange].trades)
793
+ })
794
+ }
795
+ let get_trades_id = (exchange, pair) => {
796
+ let order_info = _.get(this.order_info, [exchange, pair], {})
797
+ let timeout = setTimeout(() => {
798
+ get_trades_id(exchange, pair)
799
+ }, interval_dict[exchange].trades)
800
+ let order_number = _.keys(order_info['sell']).length + _.keys(order_info['buy']).length, count = 0, result = []
801
+ for (let type in order_info) {
802
+ for (let order_id in order_info[type]) {
803
+ Exchanges[exchange].get_trades_id(pair, order_id, trades_timeframe, (res) => {
804
+ count++
805
+ if (res.success) {
806
+ result = res.body.concat(result)
807
+ }
808
+ if (count === order_number) {
809
+ trades_handler(exchange, pair, { success: true, body: result })
810
+ clearTimeout(timeout)
811
+ setTimeout(() => {
812
+ get_trades_id(exchange, pair)
813
+ }, interval_dict[exchange].trades)
814
+ }
815
+ })
816
+ }
817
+ }
818
+ }
819
+ for (let exchange in Exchanges) {
820
+ if (this.no_trades_function_exchanges.indexOf(exchange) > -1) {
821
+
822
+ } else if (Exchanges[exchange].get_all_trades_ws) {
823
+ if (Exchanges[exchange].ws_status().trading === 'n-opened')
824
+ Exchanges[exchange].ws_account()
825
+ get_all_trades_ws(exchange)
826
+ } else if (Exchanges[exchange].get_trades_ws) {
827
+ if (Exchanges[exchange].ws_status().trading === 'n-opened')
828
+ Exchanges[exchange].ws_account()
829
+ for (let pair of exchange_pairs[exchange]) {
830
+ get_trades_ws(exchange, pair)
831
+ }
832
+ } else if (Exchanges[exchange].get_all_trades) {
833
+ get_all_trades(exchange)
834
+ } else if (Exchanges[exchange].get_trades) {
835
+ for (let pair of exchange_pairs[exchange]) {
836
+ get_trades(exchange, pair)
837
+ }
838
+ } else if (Exchanges[exchange].get_trades_id) {
839
+ for (let pair of exchange_pairs[exchange]) {
840
+ get_trades_id(exchange, pair)
841
+ }
842
+ }
843
+ }
844
+ }
845
+ get_trades_all (this.Exchanges, this.exchange_pairs, this.interval_dict)
846
+ }
847
+ check_rates () {
848
+ let rates_handler = (exchange, pair, res) => {
849
+ if (res.success) {
850
+ res.body.asks = res.body.asks.slice(0, rates_length)
851
+ res.body.bids = res.body.bids.slice(0, rates_length)
852
+ _.set(this.rates, [exchange, pair], Object.assign(res.body, { update_time: new Date() }))
853
+ for (let pair in this.pair_exchanges) {
854
+ let orderbook_all = {}, orderbook_all_with_buy_sell_limits = {},
855
+ orderbook_major = {}, orderbook_major_temp = {},
856
+ orderbook_good_with_buy_sell_limits = {}, orderbook_good_temp = {}
857
+ for (let exchange of this.pair_exchanges[pair]) {
858
+
859
+ if (_.get(this.rates, [exchange, pair, 'asks'], []).length > 0 && _.get(this.rates, [exchange, pair, 'bids'], []).length > 0) {
860
+ orderbook_all[exchange] = this.rates[exchange][pair]
861
+ } else {
862
+ orderbook_all = _.omit(orderbook_all, [exchange])
863
+ }
864
+
865
+ if (_.get(this.rates, [exchange, pair, 'asks'], []).length > 0
866
+ && _.get(this.rates, [exchange, pair, 'bids'], []).length > 0
867
+ && _.get(this.buy_sell_limits, [exchange, pair, 'buy'])
868
+ && _.get(this.buy_sell_limits, [exchange, pair, 'sell'])
869
+ ) {
870
+ let rates = JSON.parse(JSON.stringify(this.rates[exchange][pair]))
871
+ let rates_with_buy_sell_limits = {
872
+ asks: utils.sum_position_orderbook(rates.asks, this.buy_sell_limits[exchange][pair].buy),
873
+ bids: utils.vol_position_orderbook(rates.bids, this.buy_sell_limits[exchange][pair].sell)
874
+ }
875
+ orderbook_all_with_buy_sell_limits[exchange] = rates_with_buy_sell_limits
876
+ if (this.major_exchanges[pair] && this.major_exchanges[pair].indexOf(exchange) > -1) {
877
+ orderbook_major_temp[exchange] = rates
878
+ if (_.keys(orderbook_major_temp).length === this.major_exchanges[pair].length) {
879
+ orderbook_major = orderbook_major_temp
880
+ }
881
+ }
882
+ if (this.bad_trades_function_exchanges && this.bad_trades_function_exchanges.indexOf(exchange) === -1) {
883
+ orderbook_good_temp[exchange] = rates_with_buy_sell_limits
884
+ if (_.keys(orderbook_good_temp).length === this.pair_exchanges[pair].length - this.bad_trades_function_exchanges.length) {
885
+ orderbook_good_with_buy_sell_limits = orderbook_good_temp
886
+ }
887
+ }
888
+ } else {
889
+ orderbook_all_with_buy_sell_limits = _.omit(orderbook_all_with_buy_sell_limits, [exchange])
890
+ orderbook_major = _.omit(orderbook_major, [exchange])
891
+ orderbook_major_temp = _.omit(orderbook_major_temp, [exchange])
892
+ orderbook_good_with_buy_sell_limits = _.omit(orderbook_good_with_buy_sell_limits, [exchange])
893
+ orderbook_good_temp = _.omit(orderbook_good_temp, [exchange])
894
+ }
895
+ }
896
+ if (_.keys(orderbook_all).length > 0) {
897
+ let o = utils.combine_orderbooks(orderbook_all, 100)
898
+ if (o.asks.length > 0 && o.bids.length > 0) {
899
+ _.set(this.rates_combined_all, [pair], o)
900
+ } else {
901
+ this.rates_combined_all = _.omit(this.rates_combined_all, [pair])
902
+ }
903
+ }
904
+ if (_.keys(orderbook_all_with_buy_sell_limits).length > 0) {
905
+ let o = utils.combine_orderbooks(orderbook_all_with_buy_sell_limits, 100)
906
+ if (o.asks.length > 0 && o.bids.length > 0) {
907
+ _.set(this.rates_combined_all_with_buy_sell_limits, [pair], o)
908
+ } else {
909
+ this.rates_combined_all_with_buy_sell_limits = _.omit(this.rates_combined_all_with_buy_sell_limits, [pair])
910
+ }
911
+ }
912
+ if (_.keys(orderbook_major).length > 0) {
913
+ let o = utils.combine_orderbooks(orderbook_major, 100)
914
+ if (o.asks.length > 0 && o.bids.length > 0) {
915
+ _.set(this.rates_combined_major, [pair], o)
916
+ } else {
917
+ this.rates_combined_major = _.omit(this.rates_combined_major, [pair])
918
+ }
919
+ }
920
+ if (_.keys(orderbook_good_with_buy_sell_limits).length > 0) {
921
+ let o = utils.combine_orderbooks(orderbook_good_with_buy_sell_limits, 100)
922
+ if (o.asks.length > 0 && o.bids.length > 0) {
923
+ _.set(this.rates_combined_good_with_buy_sell_limits, [pair], o)
924
+ } else {
925
+ this.rates_combined_good_with_buy_sell_limits = _.omit(this.rates_combined_good_with_buy_sell_limits, [pair])
926
+ }
927
+ }
928
+ }
929
+ } else if (_.get(this.rates, [exchange, pair, 'update_time']) < new Date() - this.interval_dict[exchange].rates) {
930
+ this.error_log('%s %s rates expired: %j', exchange, pair, res)
931
+ this.rates[exchange] = _.omit(this.rates[exchange], [pair])
932
+ }
933
+ }
934
+ let get_rates = (Exchanges, exchange_pairs, interval_dict) => {
935
+ for (let exchange in Exchanges) {
936
+ if (Exchanges[exchange].ws_market) {
937
+ setInterval(() => {
938
+ if (!this.ws_market_first_time[exchange]) {
939
+ Exchanges[exchange].ws_market(exchange_pairs[exchange])
940
+ this.ws_market_first_time[exchange] = true
941
+ } else {
942
+ for (let pair of exchange_pairs[exchange]) {
943
+ Exchanges[exchange].rate_ws(pair, (res) => { rates_handler(exchange, pair, res) })
944
+ }
945
+ }
946
+ }, interval_dict[exchange].rates)
947
+ } else {
948
+ for (let pair of exchange_pairs[exchange]) {
949
+ setInterval(() => {
950
+ Exchanges[exchange].rate(pair, 30, (res) => { rates_handler(exchange, pair, res) })
951
+ }, interval_dict[exchange].rates)
952
+ }
953
+ }
954
+ }
955
+ }
956
+ get_rates (this.Exchanges, this.exchange_pairs, this.interval_dict)
957
+ }
958
+ check_market_history () {
959
+ let market_history_handler = (exchange, pair, res) => {
960
+ if (res.success) {
961
+ _.set(this.market_history, [exchange, pair], Object.assign(res.body, { update_time: new Date() }))
962
+ } else if (_.get(this.market_history, [exchange, pair, 'update_time']) < new Date() - this.interval_dict[exchange].market_history) {
963
+ this.error_log('%s %s market_history expired: %j', exchange, pair, res)
964
+ this.market_history[exchange] = _.omit(this.market_history[exchange], [pair])
965
+ }
966
+ }
967
+ let get_market_history = (Exchanges, exchange_pairs, interval_dict) => {
968
+ for (let exchange in Exchanges) {
969
+ const market_history_timeframe = (exchange === 'coinbene') ? 30 * 24 * 60 * 60 * 1000 : 10 * 60 * 1000
970
+ if (Exchanges[exchange].ws_market) {
971
+ setInterval(() => {
972
+ if (!this.ws_market_first_time[exchange]) {
973
+ Exchanges[exchange].ws_market(exchange_pairs[exchange])
974
+ this.ws_market_first_time[exchange] = true
975
+ } else {
976
+ for (let pair of exchange_pairs[exchange]) {
977
+ Exchanges[exchange].market_history_ws(pair, market_history_timeframe, (res) => { market_history_handler(exchange, pair, res) })
978
+ }
979
+ }
980
+ }, interval_dict[exchange].market_history)
981
+ } else {
982
+ for (let pair of exchange_pairs[exchange]) {
983
+ setInterval(() => {
984
+ Exchanges[exchange].market_history(pair, market_history_timeframe, (res) => { market_history_handler(exchange, pair, res) })
985
+ }, interval_dict[exchange].market_history)
986
+ }
987
+ }
988
+ }
989
+ }
990
+ get_market_history (this.Exchanges, this.exchange_pairs, this.interval_dict)
991
+ }
992
+ check_volumes () {
993
+ const influx_client = new Influx.InfluxDB(this.influx_url_check_volume)
994
+ let check_volumes_base = () => {
995
+ for (let pair in this.pair_exchanges) {
996
+ for (let exchange of this.pair_exchanges[pair]) {
997
+ let query_string = `SELECT sum("vol") FROM "${pair}" WHERE ("exchange" = '${_.upperFirst(exchange)}') AND time > now() - 12h`
998
+ influx_client.query(query_string).then(res => {
999
+ res.map(e => {
1000
+ if (e.time && e.sum) {
1001
+ _.set(this.volumes, [pair, exchange], e.sum)
1002
+ }
1003
+ })
1004
+ })
1005
+ }
1006
+ }
1007
+ }
1008
+ check_volumes_base()
1009
+ setInterval(() => {
1010
+ check_volumes_base()
1011
+ }, 15 * 60 * 1000)
1012
+ }
1013
+ check_cmc_rates () {
1014
+ let check_cmc_rates_base = () => {
1015
+ get_coinmarketcap_rates(rates => {
1016
+ this.cmc_rates = rates
1017
+ })
1018
+ }
1019
+ check_cmc_rates_base()
1020
+ setInterval(() => {
1021
+ check_cmc_rates_base()
1022
+ }, 15 * 60 * 1000)
1023
+ }
1024
+ }