forked from PRavaga/zano-trade-bot
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
189 lines (146 loc) · 5.81 KB
/
index.ts
File metadata and controls
189 lines (146 loc) · 5.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import SocketClient from './socket-client';
import { ZanoWallet } from './utils/zano-wallet';
import { FetchUtils } from './utils/fetch-methods';
import AuthParams from './interfaces/fetch-utils/AuthParams';
import logger from './logger';
import * as env from './env-vars';
import { getObservedOrder, getPairData, onOrdersNotify } from './utils/utils/utils';
import { ConfigItemParsed } from './interfaces/common/Config';
interface AvtiveThread {
socket: SocketClient;
id: string;
}
const activeThreads: AvtiveThread[] = [];
function destroyThreads() {
for (const thread of activeThreads) {
try {
thread.socket.getSocket().disconnect();
thread.socket.getSocket().removeAllListeners();
} catch (error) {
logger.error(`Failed to destroy thread ${thread.id}: ${error}`);
}
}
activeThreads.length = 0;
}
const ACTIVITY_PING_INTERVAL = 15 * 1000;
async function thread(configItem: ConfigItemParsed) {
const socketClient = new SocketClient();
const socket = await socketClient.initSocket();
const socketID = socketClient.getSocket().id;
if (!socketID) {
throw new Error('Socket initialization failed, socket ID is not available.');
}
activeThreads.push({
socket: socketClient,
id: socketID,
});
logger.detailedInfo('Starting bot...');
logger.detailedInfo('Fetching trading pair data...');
const pairData = await getPairData(configItem.pairId);
logger.detailedInfo('Fetching wallet data from Zano App...');
let tradeAuthToken: string;
const res = await ZanoWallet.getWalletData();
logger.detailedInfo(`Wallet data fetched: `);
logger.detailedInfo(res);
if (!res.alias) {
throw new Error(
'Zano App selected wallet does not have an alias. Select any wallet that has an alias.',
);
}
logger.detailedInfo('Authenticating at Zano Trade...');
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let authRes: any;
try {
authRes = await FetchUtils.auth(res as AuthParams);
} catch (err) {
logger.error(`Zano Trade auth request failed: `);
throw err;
}
if (!authRes?.success) {
throw new Error(
`Zano Trade auth request is successful, but auth failed: ${authRes.message}`,
);
} else {
tradeAuthToken = authRes.data;
}
logger.detailedInfo('Authentication successful.');
logger.detailedInfo('Getting observed order...');
const observedOrderId = await getObservedOrder(tradeAuthToken, configItem);
logger.detailedInfo(`Observed order id: ${observedOrderId}`);
(async () => {
logger.detailedInfo('Starting activity checker...');
logger.detailedInfo(
`Will ping activity checker every ${ACTIVITY_PING_INTERVAL / 1000} seconds.`,
);
async function checkThreadActivity() {
if (!activeThreads.some((thread) => thread.id === socketID)) {
return false;
}
return true;
}
while (true) {
try {
const threadActive = checkThreadActivity();
if (!threadActive) {
logger.info('Thread is not active, stopping activity checker...');
break;
}
await FetchUtils.pingActivityChecker(observedOrderId, tradeAuthToken);
} catch (error) {
console.log(error);
logger.error(`Failed to ping activity checker: ${error}`);
const threadActive = checkThreadActivity();
if (!threadActive) {
logger.info('Thread is not active, stopping activity checker...');
break;
}
logger.info('Restarting thread in 5 seconds...');
await new Promise((resolve) => setTimeout(resolve, 5000));
destroyThreads();
return startBot();
}
await new Promise((resolve) => setTimeout(resolve, ACTIVITY_PING_INTERVAL));
}
})();
await onOrdersNotify(tradeAuthToken, observedOrderId, pairData);
logger.detailedInfo('Subscribing to Zano Trade WS events...');
function setSocketListeners() {
socket.emit('in-trading', { id: configItem.pairId });
socket.on('new-order', async () => {
logger.info(
`New order message incoming via WS, starting order notification handler...`,
);
await onOrdersNotify(tradeAuthToken, observedOrderId, pairData);
});
socket.on('delete-order', async () => {
logger.info(
`Order deleted message incoming via WS, starting order notification handler...`,
);
await onOrdersNotify(tradeAuthToken, observedOrderId, pairData);
});
socket.on('update-orders', async () => {
logger.info(
`Orders update message incoming via WS, starting order notification handler...`,
);
await onOrdersNotify(tradeAuthToken, observedOrderId, pairData);
});
socket.on('disconnect', async (reason) => {
logger.warn(`Socket disconnected: ${reason}`);
logger.info('Restarting thread in 5 seconds...');
await new Promise((resolve) => setTimeout(resolve, 5000));
destroyThreads();
return startBot();
});
}
setSocketListeners();
logger.info('Bot started.');
}
async function startBot() {
for (const configItem of env.readConfig) {
logger.detailedInfo(`Starting bot for pair ${configItem.pairId}...`);
logger.detailedInfo(`Config: ${JSON.stringify(configItem)}`);
await new Promise((resolve) => setTimeout(resolve, 5000));
thread(configItem);
}
}
startBot();