@icgio/icg-exchanges-wrapper 1.14.230 → 1.14.232
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/lib/order-status-store.js +42 -21
- package/middleware/orders.js +7 -5
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const { Pool } = require('pg')
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Async PostgreSQL store for
|
|
4
|
+
* Async PostgreSQL store for all orders
|
|
5
5
|
* Non-blocking: all writes are fire-and-forget to avoid blocking the main process
|
|
6
6
|
*/
|
|
7
|
-
class
|
|
7
|
+
class AllOrdersStore {
|
|
8
8
|
constructor(connection_string) {
|
|
9
9
|
this.enabled = true
|
|
10
10
|
this.pool = null
|
|
@@ -30,7 +30,7 @@ class OpenOrdersStore {
|
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
this.pool.on('error', (err) => {
|
|
33
|
-
console.error('
|
|
33
|
+
console.error('AllOrdersStore pool error:', err.message)
|
|
34
34
|
})
|
|
35
35
|
|
|
36
36
|
// Set timezone to UTC for all connections
|
|
@@ -41,16 +41,18 @@ class OpenOrdersStore {
|
|
|
41
41
|
await this.ensure_table()
|
|
42
42
|
this.enabled = true
|
|
43
43
|
this.start_flush_interval()
|
|
44
|
-
console.log('
|
|
44
|
+
console.log('AllOrdersStore initialized successfully')
|
|
45
45
|
} catch (err) {
|
|
46
|
-
console.error('
|
|
46
|
+
console.error('AllOrdersStore init failed:', err.message)
|
|
47
47
|
this.enabled = false
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
async ensure_table() {
|
|
52
52
|
const create_table_query = `
|
|
53
|
-
|
|
53
|
+
-- All orders (persistent mapping of id/order_id to order_type & status)
|
|
54
|
+
CREATE TABLE IF NOT EXISTS all_orders (
|
|
55
|
+
id VARCHAR(128),
|
|
54
56
|
exchange VARCHAR(64) NOT NULL,
|
|
55
57
|
pair VARCHAR(32) NOT NULL,
|
|
56
58
|
order_type VARCHAR(64),
|
|
@@ -66,12 +68,11 @@ class OpenOrdersStore {
|
|
|
66
68
|
open_time TIMESTAMPTZ,
|
|
67
69
|
close_time TIMESTAMPTZ,
|
|
68
70
|
note VARCHAR(256),
|
|
71
|
+
created_at TIMESTAMPTZ DEFAULT (NOW() AT TIME ZONE 'UTC'),
|
|
69
72
|
updated_at TIMESTAMPTZ DEFAULT (NOW() AT TIME ZONE 'UTC'),
|
|
70
73
|
PRIMARY KEY (exchange, pair, type, order_id)
|
|
71
74
|
);
|
|
72
|
-
CREATE INDEX IF NOT EXISTS
|
|
73
|
-
CREATE INDEX IF NOT EXISTS idx_open_orders_exchange ON open_orders(exchange);
|
|
74
|
-
CREATE INDEX IF NOT EXISTS idx_open_orders_ex_pair_order ON open_orders(exchange, pair, order_id);
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_all_orders_exchange_pair_order ON all_orders(exchange, pair, order_id);
|
|
75
76
|
`
|
|
76
77
|
|
|
77
78
|
const client = await this.pool.connect()
|
|
@@ -83,12 +84,27 @@ class OpenOrdersStore {
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Remove all rows for a specific exchange/pair (fresh start).
|
|
89
|
+
* @param {string} exchange
|
|
90
|
+
* @param {string} pair
|
|
91
|
+
*/
|
|
92
|
+
async clear_orders(exchange, pair) {
|
|
93
|
+
if (!this.enabled || !this.table_ready) return
|
|
94
|
+
const client = await this.pool.connect()
|
|
95
|
+
try {
|
|
96
|
+
await client.query('DELETE FROM all_orders WHERE exchange = $1 AND pair = $2', [exchange, pair])
|
|
97
|
+
} finally {
|
|
98
|
+
client.release()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
start_flush_interval() {
|
|
87
103
|
if (this.flush_interval) return
|
|
88
104
|
|
|
89
105
|
this.flush_interval = setInterval(() => {
|
|
90
106
|
this.flush().catch((err) => {
|
|
91
|
-
console.error('
|
|
107
|
+
console.error('AllOrdersStore flush error:', err.message)
|
|
92
108
|
})
|
|
93
109
|
}, this.flush_interval_ms)
|
|
94
110
|
}
|
|
@@ -122,6 +138,7 @@ class OpenOrdersStore {
|
|
|
122
138
|
}
|
|
123
139
|
|
|
124
140
|
const record = {
|
|
141
|
+
id: data.id,
|
|
125
142
|
exchange,
|
|
126
143
|
pair,
|
|
127
144
|
type,
|
|
@@ -155,13 +172,14 @@ class OpenOrdersStore {
|
|
|
155
172
|
|
|
156
173
|
const batch = this.queue.splice(0, 100) // Process up to 100 at a time
|
|
157
174
|
|
|
158
|
-
const
|
|
159
|
-
INSERT INTO
|
|
160
|
-
exchange, pair, type, order_id, order_type, status,
|
|
175
|
+
const upsert_all_orders_query = `
|
|
176
|
+
INSERT INTO all_orders (
|
|
177
|
+
id, exchange, pair, type, order_id, order_type, status,
|
|
161
178
|
price, amount, f_amount, f_percentage, t_amount,
|
|
162
|
-
fees, open_time, close_time, note, updated_at
|
|
163
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, (NOW() AT TIME ZONE 'UTC'))
|
|
179
|
+
fees, open_time, close_time, note, created_at, updated_at
|
|
180
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, (NOW() AT TIME ZONE 'UTC'), (NOW() AT TIME ZONE 'UTC'))
|
|
164
181
|
ON CONFLICT (exchange, pair, type, order_id) DO UPDATE SET
|
|
182
|
+
id = EXCLUDED.id,
|
|
165
183
|
order_type = EXCLUDED.order_type,
|
|
166
184
|
status = EXCLUDED.status,
|
|
167
185
|
price = EXCLUDED.price,
|
|
@@ -176,8 +194,8 @@ class OpenOrdersStore {
|
|
|
176
194
|
updated_at = (NOW() AT TIME ZONE 'UTC')
|
|
177
195
|
`
|
|
178
196
|
|
|
179
|
-
const
|
|
180
|
-
DELETE FROM
|
|
197
|
+
const delete_all_orders_query = `
|
|
198
|
+
DELETE FROM all_orders
|
|
181
199
|
WHERE exchange = $1 AND pair = $2 AND type = $3 AND order_id = $4
|
|
182
200
|
`
|
|
183
201
|
|
|
@@ -185,9 +203,12 @@ class OpenOrdersStore {
|
|
|
185
203
|
try {
|
|
186
204
|
for (const record of batch) {
|
|
187
205
|
if (record.status === 'DELETED') {
|
|
188
|
-
|
|
206
|
+
// Physically delete rows for deleted orders to limit DB size
|
|
207
|
+
await client.query(delete_all_orders_query, [record.exchange, record.pair, record.type, record.order_id])
|
|
189
208
|
} else {
|
|
190
|
-
|
|
209
|
+
// Upsert active / updated orders
|
|
210
|
+
await client.query(upsert_all_orders_query, [
|
|
211
|
+
record.id,
|
|
191
212
|
record.exchange,
|
|
192
213
|
record.pair,
|
|
193
214
|
record.type,
|
|
@@ -221,7 +242,7 @@ class OpenOrdersStore {
|
|
|
221
242
|
try {
|
|
222
243
|
await this.flush()
|
|
223
244
|
} catch (err) {
|
|
224
|
-
console.error('
|
|
245
|
+
console.error('AllOrdersStore final flush error:', err.message)
|
|
225
246
|
}
|
|
226
247
|
}
|
|
227
248
|
if (this.pool) {
|
|
@@ -231,4 +252,4 @@ class OpenOrdersStore {
|
|
|
231
252
|
}
|
|
232
253
|
}
|
|
233
254
|
|
|
234
|
-
module.exports =
|
|
255
|
+
module.exports = AllOrdersStore
|
package/middleware/orders.js
CHANGED
|
@@ -7,7 +7,7 @@ const utils = require('@icgio/icg-utils').utils
|
|
|
7
7
|
const { coinmarketcap: get_coinmarketcap_rates, observable: Observable } = require('@icgio/icg-utils')
|
|
8
8
|
|
|
9
9
|
const Account = require('./account.js')
|
|
10
|
-
const
|
|
10
|
+
const AllOrdersStore = require('../lib/order-status-store.js')
|
|
11
11
|
|
|
12
12
|
// Default precision functions - will be overridden if provided in settings
|
|
13
13
|
let round_price = (exchange, pair, price) => price
|
|
@@ -125,8 +125,8 @@ module.exports = class Orders {
|
|
|
125
125
|
this.accounting_benchmark = settings.accounting_benchmark
|
|
126
126
|
this.balance_benchmark = settings.balance_benchmark || {}
|
|
127
127
|
this.min_reserve_balance = settings.min_reserve_balance || {}
|
|
128
|
-
// Initialize
|
|
129
|
-
this.
|
|
128
|
+
// Initialize all orders store for PostgreSQL persistence (async, non-blocking)
|
|
129
|
+
this.all_orders_store = new AllOrdersStore(cd.all_orders_store_connection_string)
|
|
130
130
|
for (let exchange in exchange_pairs) {
|
|
131
131
|
let api_key_temp = cd[exchange]['api_keys'] || cd[exchange]['api_key'],
|
|
132
132
|
secret_key_temp = cd[exchange]['secret_keys'] || cd[exchange]['secret_key'],
|
|
@@ -758,14 +758,14 @@ module.exports = class Orders {
|
|
|
758
758
|
// end: log every f-filled trade for future analysis
|
|
759
759
|
// Store order status to PostgreSQL asynchronously (non-blocking)
|
|
760
760
|
const order_data = _.get(this.order_info, [exchange, pair, type, order_id], {})
|
|
761
|
-
this.
|
|
761
|
+
this.all_orders_store.store(exchange, pair, type, order_id, order_data, note)
|
|
762
762
|
}
|
|
763
763
|
delete_order_info(exchange, pair, type, order_id, note) {
|
|
764
764
|
const order_data = _.get(this.order_info, [exchange, pair, type, order_id], {})
|
|
765
765
|
this.order_info[exchange][pair][type] = _.omit(this.order_info[exchange][pair][type], [order_id])
|
|
766
766
|
console.log('DELETE %s: %s %s %s %s', note, exchange, pair, type, order_id)
|
|
767
767
|
// Store deletion to PostgreSQL (non-blocking)
|
|
768
|
-
this.
|
|
768
|
+
this.all_orders_store.store(exchange, pair, type, order_id, { ...order_data, status: 'DELETED' }, note)
|
|
769
769
|
}
|
|
770
770
|
check_balances() {
|
|
771
771
|
let balances_handler = (exchange, res) => {
|
|
@@ -886,6 +886,8 @@ module.exports = class Orders {
|
|
|
886
886
|
}
|
|
887
887
|
// cancel previous orders
|
|
888
888
|
else if (this.cancel_previous_orders && !this.previous_orders_canceled) {
|
|
889
|
+
// remove all previous orders for this exchange/pair from all_orders (fire-and-forget)
|
|
890
|
+
this.all_orders_store.clear_orders(exchange, pair).catch((err) => console.error('clear_all_orders error', exchange, pair, err.message))
|
|
889
891
|
if (this.cancel_previous_orders_with_delay) {
|
|
890
892
|
setTimeout(() => {
|
|
891
893
|
orders.map((order) => {
|