@icgio/icg-exchanges-wrapper 1.14.254 → 1.14.256
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.
package/README.md
CHANGED
|
@@ -1 +1,129 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ICG Exchanges Wrapper
|
|
2
|
+
|
|
3
|
+
High-level wrapper functions for the ICG exchanges package, providing simplified interfaces for common trading operations across multiple exchanges.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multi-Exchange Operations**: Execute operations across multiple exchanges in parallel
|
|
8
|
+
- **Unified Data Format**: Consistent response format regardless of exchange
|
|
9
|
+
- **Order Management Middleware**: Advanced order placement with retries and validation
|
|
10
|
+
- **WebSocket Data Client**: Real-time log streaming support
|
|
11
|
+
- **Rate Data Aggregation**: Combine orderbook data from multiple sources
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @icgio/icg-exchanges-wrapper
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Functions Module
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
const { functions } = require('@icgio/icg-exchanges-wrapper')
|
|
25
|
+
|
|
26
|
+
// Get rates (orderbook) from multiple exchanges
|
|
27
|
+
const rates = await functions.get_exchanges_rates(exchanges, pairs)
|
|
28
|
+
|
|
29
|
+
// Get balances from multiple exchanges
|
|
30
|
+
const balances = await functions.get_exchanges_balance(exchanges)
|
|
31
|
+
|
|
32
|
+
// Get trade history
|
|
33
|
+
const trades = await functions.get_exchanges_trades(exchanges, pairs)
|
|
34
|
+
|
|
35
|
+
// Get open orders
|
|
36
|
+
const open_orders = await functions.get_exchanges_open_orders(exchanges, pairs)
|
|
37
|
+
|
|
38
|
+
// Get deposit history
|
|
39
|
+
const deposits = await functions.get_exchanges_deposits(exchanges)
|
|
40
|
+
|
|
41
|
+
// Get withdrawal history
|
|
42
|
+
const withdrawals = await functions.get_exchanges_withdrawals(exchanges)
|
|
43
|
+
|
|
44
|
+
// Get OHLCV data
|
|
45
|
+
const ohlcv = await functions.get_exchanges_ohlcv(exchanges, pairs, interval)
|
|
46
|
+
|
|
47
|
+
// Get market history
|
|
48
|
+
const market_history = await functions.get_exchanges_market_history(exchanges, pairs)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Orders Middleware
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
const Orders = require('@icgio/icg-exchanges-wrapper').orders
|
|
55
|
+
|
|
56
|
+
// Create an order manager instance
|
|
57
|
+
const orders = new Orders(exchanges_config)
|
|
58
|
+
|
|
59
|
+
// Place orders with advanced features
|
|
60
|
+
await orders.place_order(exchange, pair, side, amount, price, options)
|
|
61
|
+
|
|
62
|
+
// Cancel orders
|
|
63
|
+
await orders.cancel_order(exchange, pair, order_id)
|
|
64
|
+
|
|
65
|
+
// Get order status
|
|
66
|
+
const status = await orders.get_order_status(exchange, pair, order_id)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### WebSocket Data Client
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
const { ws_data_client, send_log } = require('@icgio/icg-exchanges-wrapper')
|
|
73
|
+
|
|
74
|
+
// Send log messages via WebSocket
|
|
75
|
+
send_log('info', 'Operation completed successfully')
|
|
76
|
+
send_log('error', 'An error occurred')
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Project Structure
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
icg-exchanges-wrapper/
|
|
83
|
+
├── index.js # Main entry point
|
|
84
|
+
├── functions/
|
|
85
|
+
│ ├── get-exchanges-balance.js # Balance fetching
|
|
86
|
+
│ ├── get-exchanges-deposits.js # Deposit history
|
|
87
|
+
│ ├── get-exchanges-open-orders.js # Open orders
|
|
88
|
+
│ ├── get-exchanges-rates-market-history-ohlcv.js # Market data
|
|
89
|
+
│ ├── get-exchanges-trades.js # Trade history
|
|
90
|
+
│ └── get-exchanges-withdrawals.js # Withdrawal history
|
|
91
|
+
├── middleware/
|
|
92
|
+
│ ├── account.js # Account middleware
|
|
93
|
+
│ └── orders.js # Order management middleware
|
|
94
|
+
├── lib/
|
|
95
|
+
│ └── ws-data-client.js # WebSocket data client
|
|
96
|
+
└── package.json
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Available Functions
|
|
100
|
+
|
|
101
|
+
| Function | Description |
|
|
102
|
+
|----------|-------------|
|
|
103
|
+
| `get_exchanges_rates` | Fetch orderbook/rates from exchanges |
|
|
104
|
+
| `get_exchanges_market_history` | Fetch recent trade history |
|
|
105
|
+
| `get_exchanges_ohlcv` | Fetch OHLCV candlestick data |
|
|
106
|
+
| `get_exchanges_balance` | Fetch account balances |
|
|
107
|
+
| `get_exchanges_trades` | Fetch user trade history |
|
|
108
|
+
| `get_exchanges_open_orders` | Fetch open orders |
|
|
109
|
+
| `get_exchanges_deposits` | Fetch deposit history |
|
|
110
|
+
| `get_exchanges_withdrawals` | Fetch withdrawal history |
|
|
111
|
+
|
|
112
|
+
## Dependencies
|
|
113
|
+
|
|
114
|
+
| Package | Purpose |
|
|
115
|
+
|---------|---------|
|
|
116
|
+
| `@icgio/icg-exchanges` | Exchange implementations |
|
|
117
|
+
| `@icgio/icg-utils` | Utility functions |
|
|
118
|
+
| `lodash` | Utility library |
|
|
119
|
+
| `pg` | PostgreSQL client |
|
|
120
|
+
|
|
121
|
+
## Code Style
|
|
122
|
+
|
|
123
|
+
- CommonJS modules (`require()` / `module.exports`)
|
|
124
|
+
- Variable naming: `snake_case`
|
|
125
|
+
- Function naming: `snake_case`
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
ISC License
|
|
@@ -25,11 +25,48 @@ const get_exchanges_rates = function (Exchanges, exchange_pair_dict, cb, ws_enab
|
|
|
25
25
|
}
|
|
26
26
|
if (Exchange.ws_market && ws_enabled) {
|
|
27
27
|
let ws_promise = new Promise((resolve, reject) => {
|
|
28
|
+
if (!Exchange.ws || !Exchange.ws.market) {
|
|
29
|
+
console.error(`${Exchange_name} WebSocket not properly initialized`)
|
|
30
|
+
reject(new Error(`WebSocket not initialized for ${Exchange_name}`))
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
Exchange.ws_market(exchange_pair_dict[Exchange_name])
|
|
29
35
|
|
|
36
|
+
const WS_TIMEOUT_MS = 30000 // 30 seconds timeout
|
|
37
|
+
const start_time = Date.now()
|
|
38
|
+
let check_count = 0
|
|
39
|
+
const MAX_CHECKS = 300 // 30 seconds / 100ms
|
|
40
|
+
|
|
30
41
|
const check_status = () => {
|
|
42
|
+
check_count++
|
|
43
|
+
const elapsed = Date.now() - start_time
|
|
44
|
+
|
|
45
|
+
// Timeout check
|
|
46
|
+
if (elapsed > WS_TIMEOUT_MS || check_count > MAX_CHECKS) {
|
|
47
|
+
console.error(`WebSocket timeout for ${Exchange_name} after ${elapsed}ms`)
|
|
48
|
+
reject(new Error(`WebSocket timeout for ${Exchange_name}`))
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Safety check for WebSocket object
|
|
53
|
+
if (!Exchange.ws || !Exchange.ws.market) {
|
|
54
|
+
console.error(`${Exchange_name} WebSocket object missing during check`)
|
|
55
|
+
reject(new Error(`WebSocket object missing for ${Exchange_name}`))
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
31
59
|
let all_pairs_opened = exchange_pair_dict[Exchange_name].every((pair) => {
|
|
32
|
-
return
|
|
60
|
+
return (
|
|
61
|
+
Exchange.ws.market.pair_status &&
|
|
62
|
+
Exchange.ws.market.pair_status[pair] === 'opened' &&
|
|
63
|
+
Exchange.ws.market.asks_dict &&
|
|
64
|
+
Exchange.ws.market.asks_dict[pair] &&
|
|
65
|
+
Exchange.ws.market.asks_dict[pair].length > 0 &&
|
|
66
|
+
Exchange.ws.market.bids_dict &&
|
|
67
|
+
Exchange.ws.market.bids_dict[pair] &&
|
|
68
|
+
Exchange.ws.market.bids_dict[pair].length > 0
|
|
69
|
+
)
|
|
33
70
|
})
|
|
34
71
|
if (all_pairs_opened) {
|
|
35
72
|
let rate_promises = exchange_pair_dict[Exchange_name].map((pair) => {
|
|
@@ -129,6 +166,7 @@ const get_exchanges_rates = function (Exchanges, exchange_pair_dict, cb, ws_enab
|
|
|
129
166
|
})
|
|
130
167
|
.catch((error) => {
|
|
131
168
|
console.error('Error in fetching exchange rates:', error)
|
|
169
|
+
// Still call callback with available data even if some promises failed
|
|
132
170
|
cb({ exchange_pair_rates, pair_exchange_rates })
|
|
133
171
|
})
|
|
134
172
|
}
|
|
@@ -154,13 +192,48 @@ const get_exchanges_market_history = function (Exchanges, exchange_pair_dict, ti
|
|
|
154
192
|
}
|
|
155
193
|
if (Exchange.ws_market && ws_enabled) {
|
|
156
194
|
let ws_promise = new Promise((resolve, reject) => {
|
|
195
|
+
if (!Exchange.ws || !Exchange.ws.market) {
|
|
196
|
+
console.error(`${Exchange_name} WebSocket not properly initialized`)
|
|
197
|
+
reject(new Error(`WebSocket not initialized for ${Exchange_name}`))
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
|
|
157
201
|
if (!first_time[Exchange_name]) {
|
|
158
202
|
Exchange.ws_market(exchange_pair_dict[Exchange_name])
|
|
159
203
|
first_time[Exchange_name] = true
|
|
160
204
|
}
|
|
205
|
+
|
|
206
|
+
const WS_TIMEOUT_MS = 30000 // 30 seconds timeout
|
|
207
|
+
const start_time = Date.now()
|
|
208
|
+
let check_count = 0
|
|
209
|
+
const MAX_CHECKS = 300 // 30 seconds / 100ms
|
|
210
|
+
|
|
161
211
|
const check_status = () => {
|
|
212
|
+
check_count++
|
|
213
|
+
const elapsed = Date.now() - start_time
|
|
214
|
+
|
|
215
|
+
// Timeout check
|
|
216
|
+
if (elapsed > WS_TIMEOUT_MS || check_count > MAX_CHECKS) {
|
|
217
|
+
console.error(`WebSocket timeout for ${Exchange_name} market history after ${elapsed}ms`)
|
|
218
|
+
reject(new Error(`WebSocket timeout for ${Exchange_name} market history`))
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Safety check for WebSocket object
|
|
223
|
+
if (!Exchange.ws || !Exchange.ws.market) {
|
|
224
|
+
console.error(`${Exchange_name} WebSocket object missing during check`)
|
|
225
|
+
reject(new Error(`WebSocket object missing for ${Exchange_name}`))
|
|
226
|
+
return
|
|
227
|
+
}
|
|
228
|
+
|
|
162
229
|
let all_pairs_opened = exchange_pair_dict[Exchange_name].every((pair) => {
|
|
163
|
-
return
|
|
230
|
+
return (
|
|
231
|
+
Exchange.ws.market.pair_status &&
|
|
232
|
+
Exchange.ws.market.pair_status[pair] === 'opened' &&
|
|
233
|
+
Exchange.ws.market.market_history_dict &&
|
|
234
|
+
Exchange.ws.market.market_history_dict[pair] &&
|
|
235
|
+
Exchange.ws.market.market_history_dict[pair].length >= 0
|
|
236
|
+
)
|
|
164
237
|
})
|
|
165
238
|
if (all_pairs_opened) {
|
|
166
239
|
let market_history_promises = exchange_pair_dict[Exchange_name].map((pair) => {
|
|
@@ -237,6 +310,8 @@ let checked_ohlcv_exchange = {},
|
|
|
237
310
|
pair_exchange_ohlcv = {}
|
|
238
311
|
const get_exchanges_ohlcv = function (Exchanges, exchange_pair_dict, from_in_ms, to_in_ms, cb) {
|
|
239
312
|
checked_ohlcv_exchange = {}
|
|
313
|
+
ohlcv_status = {}
|
|
314
|
+
ohlcv_status._callback_fired = false // Reset callback flag
|
|
240
315
|
if (!Array.isArray(Exchanges)) {
|
|
241
316
|
console.error('Exchanges should be an array')
|
|
242
317
|
return
|
|
@@ -267,13 +342,17 @@ const get_exchanges_ohlcv = function (Exchanges, exchange_pair_dict, from_in_ms,
|
|
|
267
342
|
}
|
|
268
343
|
}
|
|
269
344
|
_.set(ohlcv_status, [Exchange_name + pair], true)
|
|
270
|
-
|
|
345
|
+
// Use a flag to prevent multiple callback calls
|
|
346
|
+
if (!_.includes(_.values(ohlcv_status), false) && !ohlcv_status._callback_fired) {
|
|
347
|
+
ohlcv_status._callback_fired = true
|
|
271
348
|
cb({ exchange_pair_ohlcv, pair_exchange_ohlcv })
|
|
272
349
|
}
|
|
273
350
|
})
|
|
274
351
|
} else {
|
|
275
352
|
_.set(ohlcv_status, [Exchange_name + pair], true)
|
|
276
|
-
|
|
353
|
+
// Use a flag to prevent multiple callback calls
|
|
354
|
+
if (!_.includes(_.values(ohlcv_status), false) && !ohlcv_status._callback_fired) {
|
|
355
|
+
ohlcv_status._callback_fired = true
|
|
277
356
|
cb({ exchange_pair_ohlcv, pair_exchange_ohlcv })
|
|
278
357
|
}
|
|
279
358
|
}
|
package/middleware/account.js
CHANGED
|
@@ -130,11 +130,11 @@ module.exports = class Account {
|
|
|
130
130
|
if (_.includes(constants.stablecoins, cur)) {
|
|
131
131
|
profit.USD += position
|
|
132
132
|
} else if (_.includes(['KRW'], cur)) {
|
|
133
|
-
profit.USD += position
|
|
133
|
+
profit.USD += position * this.forex_rates['KRWUSD']
|
|
134
134
|
} else if (_.includes(['HKD'], cur)) {
|
|
135
|
-
profit.USD += position
|
|
135
|
+
profit.USD += position * this.forex_rates['HKDUSD']
|
|
136
136
|
} else if (_.includes(['CNYT'], cur)) {
|
|
137
|
-
profit.USD += position
|
|
137
|
+
profit.USD += position * this.forex_rates['CNYUSD']
|
|
138
138
|
} else {
|
|
139
139
|
if (!cmc_rates[cur]) {
|
|
140
140
|
console.log('get_exchange_profit rates_cmc %s does not exist', cur)
|
package/middleware/orders.js
CHANGED