market-data-tradingview-ws 0.0.1

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.
File without changes
package/.prettierrc ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "singleQuote": true,
3
+ "trailingComma": "all",
4
+ "printWidth": 140,
5
+ "arrowParens": "always",
6
+ "overrides": [
7
+ {
8
+ "files": ["**/.*rc", "**/*.json"],
9
+ "options": { "parser": "json" }
10
+ }
11
+ ]
12
+ }
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ 'use strict';
2
+
3
+ import { Client } from './lib/client.js';
4
+
5
+ exports.default = Client;
6
+ module.exports = Client;
package/lib/client.js ADDED
@@ -0,0 +1,156 @@
1
+ import WebSocket from 'ws';
2
+ import { tradingView } from './tradingView.js';
3
+
4
+ const tv = new tradingView();
5
+
6
+ const sessions = {
7
+ values: new Map(),
8
+
9
+ set({ key, data }) {
10
+ if (data) {
11
+ this.values.set(key, data);
12
+ }
13
+ },
14
+ get({ key }) {
15
+ return this.values.get(key);
16
+ },
17
+ getKeys() {
18
+ return this.values.keys();
19
+ },
20
+ getKeyByType({ type }) {
21
+ let session = '';
22
+ this.values.forEach((value, key) => {
23
+ if (type === value.type) session = key;
24
+ });
25
+ return session;
26
+ },
27
+ };
28
+
29
+ export class Client {
30
+ #ws;
31
+ #sessions; // = new Map();
32
+ #token = null;
33
+ constructor() {
34
+ this.#sessions = sessions;
35
+ }
36
+
37
+ close() {
38
+ this.#ws.close();
39
+ }
40
+
41
+ getSession({ key }) {
42
+ return this.#sessions.get({ key });
43
+ }
44
+
45
+ getSessionKeys() {
46
+ return this.#sessions.keys();
47
+ }
48
+
49
+ async getToken({ login, pass }) {
50
+ return tv.getToken({ login, pass });
51
+ }
52
+
53
+ auth(token = ['unauthorized_user_token']) {
54
+ return tv.formatWSPacket({
55
+ packet: {
56
+ m: 'set_auth_token',
57
+ p: [token],
58
+ },
59
+ });
60
+ }
61
+
62
+ async connect({ url, options, login, pass, result }) {
63
+ this.#token = await this.getToken({ login, pass });
64
+ if (this.#token.length > 10) {
65
+ return new Promise((resolv, reject) => {
66
+ this.#ws = new WebSocket(url, options);
67
+
68
+ this.#ws.onclose = () => console.log('disconnected');
69
+
70
+ this.#ws.onerror = (error) => reject(console.error('error: ', error));
71
+ this.#ws.onopen = () => {
72
+ this.#ws.send(this.auth(this.#token));
73
+ this.messageListner({ result });
74
+ resolv('open');
75
+ };
76
+ });
77
+ }
78
+ }
79
+
80
+ createSession({ type }) {
81
+ const startsWith = type === 'chart' ? 'cs_' : 'qs_';
82
+ const key = tv.createSession({ startsWith });
83
+ const session = sessions.set({ key, data: { type, symbols: [] } });
84
+ // console.log(key, session);
85
+ if (type === 'chart') {
86
+ this.#ws.send(tv.wsCreateChartSession({ chartSession: key }));
87
+ this.#ws.send(tv.switchTimezone({ chartSession: key, tz: 'Etc/UTC' }));
88
+ } else {
89
+ this.#ws.send(tv.wsQuoteCreateSession({ session: key }));
90
+ this.#ws.send(tv.setFieldsChart({ session: key }));
91
+ }
92
+ return session;
93
+ }
94
+
95
+ addQuoteSymbols({ symbolIds }) {
96
+ const key = this.#sessions.getKeyByType({ type: 'quote' });
97
+ this.#ws.send(tv.quoteAddSymbols({ session: key, symbolIds }));
98
+
99
+ const data = this.#sessions.get({ key });
100
+ // console.log(key, data);
101
+ symbolIds.forEach((each) => data.symbols.push(each));
102
+ this.#sessions.set({ key, data });
103
+ }
104
+
105
+ messageListner({ result }) {
106
+ this.#ws.on('message', (raw) => {
107
+ if (this.#ws.readyState !== this.#ws.OPEN) return;
108
+
109
+ let session = '';
110
+ tv.parsePacket({ str: raw }).forEach((packet) => {
111
+ if (packet === undefined) {
112
+ console.log('undefined: ', raw.toString());
113
+ } else {
114
+ if (packet.type === 'ping') {
115
+ // console.info('pong', packet);
116
+ this.#ws.send(tv.createPong({ value: packet.data }));
117
+ } else if (packet.type === 'protocol_error') {
118
+ console.warn('protocol_error', packet);
119
+ this.close();
120
+ } else if (packet.type === 'qsd') {
121
+ session = sessions.get({ key: packet.data[0] });
122
+ // console.log('qsd', packet.data, session);
123
+ const send = packet.data[1].v;
124
+ send.symbol = packet.data[1].n;
125
+ // console.log(JSON.stringify([packet.type, send]));
126
+ result({ packet: send });
127
+ } else if (['du', 'timescale_update'].includes(packet.type)) {
128
+ session = sessions.get({ key: packet.data[0] });
129
+ // console.log('du', packet.data, session);
130
+ result({ packet });
131
+ // const arr = [];
132
+ // for (var key in packet.data[1].s1.s) {
133
+ // const send = {
134
+ // symbol: session.symbolId,
135
+ // end: packet.data[1].s1.s[key + 1] !== undefined ? packet.data[1].s1.s[key + 1].v[0] : packet.data[1].s1.lbs.bar_close_time,
136
+ // };
137
+ // console.log(key, packet.data[1].s1.s);
138
+ // [send.start, send.open, send.low, send.high, send.close, send.passed] = packet.data[1].s1.s[key].v;
139
+ // console.log(send);
140
+ // arr.push(send);
141
+ // }
142
+ // [send.start, send.open, send.low, send.high, send.close, send.passed] = packet.data[1].s1.s.v;
143
+ // console.log(JSON.stringify([packet.type, arr]));
144
+ } else if (['series', 'symbol', 'quote'].includes(packet.type)) {
145
+ console.info(packet);
146
+ } else {
147
+ console.warn('error', raw.toString());
148
+ }
149
+ // else {
150
+ // console.log('received: %s', raw);
151
+ // }
152
+ }
153
+ });
154
+ });
155
+ }
156
+ }
@@ -0,0 +1,217 @@
1
+ import { Utils } from './utils.js';
2
+ const u = new Utils();
3
+
4
+ const letters = 'abcdefghijklmnopqrstuvwxyz';
5
+ const cleanerRgx = /~h~/g;
6
+ const splitterRgx = /~m~[0-9]{1,}~m~/g;
7
+ const urlSymbolSearch = 'https://symbol-search.tradingview.com/symbol_search';
8
+
9
+ export class tradingView {
10
+ async getToken({ login, pass }) {
11
+ const url = 'https://www.tradingview.com/accounts/signin/';
12
+ const headers = {
13
+ Referer: 'https://www.tradingview.com',
14
+ };
15
+
16
+ const form = new FormData();
17
+ form.append('username', login);
18
+ form.append('password', pass);
19
+ form.append('remember', 'on');
20
+
21
+ // const res = await fetch(url, {
22
+ // method: 'POST',
23
+ // headers,
24
+ // body: form,
25
+ // });
26
+
27
+ // if (res.status === 200) {
28
+ // const data = await res.json();
29
+ // if (data.user.auth_token === undefined) throw new Error('Error get auth_token', data);
30
+ // console.log(data.user.auth_token);
31
+ // return data.user.auth_token;
32
+ // }
33
+
34
+ // await u.pause();
35
+ return 'eyJhbGciOiJSUzUxMiIsImtpZCI6IkdaeFUiLCJ0eXAiOiJKV1QifQ.eyJ1c2VyX2lkIjoxMjI1ODcxMiwiZXhwIjoxNjkwNzkzMjIwLCJpYXQiOjE2OTA3Nzg4MjAsInBsYW4iOiJwcm9fcHJlbWl1bSIsImV4dF9ob3VycyI6MSwicGVybSI6IiIsInN0dWR5X3Blcm0iOiJ0di1jaGFydF9wYXR0ZXJucyx0di1jaGFydHBhdHRlcm5zLHR2LXByb3N0dWRpZXMsdHYtdm9sdW1lYnlwcmljZSIsIm1heF9zdHVkaWVzIjoyNSwibWF4X2Z1bmRhbWVudGFscyI6MCwibWF4X2NoYXJ0cyI6OCwibWF4X2FjdGl2ZV9hbGVydHMiOjQwMCwibWF4X3N0dWR5X29uX3N0dWR5IjoyNCwibWF4X2FjdGl2ZV9wcmltaXRpdmVfYWxlcnRzIjo0MDAsIm1heF9hY3RpdmVfY29tcGxleF9hbGVydHMiOjQwMCwibWF4X2Nvbm5lY3Rpb25zIjo1MH0.pZQgM_oTZMnm1Qb4qBf6CfM9dHKltp2T3O2g_VVoK9l66UngEL8mLdeH7-ZpUZ8Y50rV5yr0ND8WRPsRH2w2izk_SNMD63p6GJzXXGPvILgirXW3SFa7HmaHv8Xp6SPhQTWb-ahyv_2GUIueKTvHWBNF5-eBnqYeoXQeWkRFsLA';
36
+ }
37
+
38
+ async getSymbol({ symbol, type }) {
39
+ // type = 'stock' | 'futures' | 'forex' | 'cfd' | 'crypto' | 'index' | 'economic'
40
+ // query = what you want to search!
41
+ // it returns first matching item
42
+ const res = await fetch(urlSymbolSearch + '?text=' + symbol + '&type=' + type);
43
+ if (res.status === 200) {
44
+ const data = await res.json();
45
+ // console.log(data);
46
+ return data[0];
47
+ }
48
+
49
+ return 'Network Error!';
50
+ }
51
+
52
+ getSymbolId({ data }) {
53
+ const name = data.type === 'futures' ? data.contracts[0].symbol : data.symbol;
54
+ return data.exchange.toUpperCase() + ':' + name.toUpperCase();
55
+ }
56
+
57
+ createSession({ startsWith }) {
58
+ let session = startsWith;
59
+ while (session.length < 12) {
60
+ session += letters[Math.floor(Math.random() * letters.length)];
61
+ }
62
+ return session;
63
+ }
64
+
65
+ formatWSPacket({ packet }) {
66
+ const msg = typeof packet === 'object' ? JSON.stringify(packet) : packet;
67
+ return '~m~' + msg.length + '~m~' + msg;
68
+ }
69
+
70
+ parsePacket({ str }) {
71
+ const messages = [];
72
+ this.parseWSPacket({ str }).forEach((packet) => {
73
+ messages.push(this.eachPacket(packet));
74
+ });
75
+ return messages;
76
+ }
77
+
78
+ parseWSPacket({ str }) {
79
+ return str
80
+ .toString()
81
+ .replace(cleanerRgx, '')
82
+ .split(splitterRgx)
83
+ .map((p) => {
84
+ if (!p) return false;
85
+ try {
86
+ return JSON.parse(p);
87
+ } catch (error) {
88
+ console.warn('Cant parse', p);
89
+ return false;
90
+ }
91
+ })
92
+ .filter((p) => p);
93
+ }
94
+
95
+ eachPacket(packet) {
96
+ if (typeof packet === 'number') {
97
+ return { type: 'ping', data: packet }; // Ping
98
+ } else if (packet.m && packet.p) {
99
+ // Normal packet
100
+ if (packet.m.startsWith('du')) return { type: packet.m, data: packet.p };
101
+ if (packet.m.startsWith('timescale') || packet.m.startsWith('qsd')) return { type: packet.m, data: packet.p };
102
+ if (packet.m.startsWith('series') || packet.m.startsWith('symbol') || packet.m.startsWith('quote')) {
103
+ const type = packet.m.split('_');
104
+ return { type: type[0], data: { sub: type[1], detail: packet.p, time: packet.t_ms ? packet.t_ms : Date.now() } };
105
+ } else {
106
+ return { type: 'msg', data: parsed.data };
107
+ }
108
+ // const session = packet.p[0];
109
+
110
+ // if (session && this.#sessions[session]) {
111
+ // this.#sessions[session].onData(parsed);
112
+ //
113
+ // }
114
+ } else if (packet.session_id) {
115
+ return { type: 'session', data: packet };
116
+ } else if (packet.m === 'protocol_error') {
117
+ return { type: packet.m, data: packet.p }; // Error
118
+ } else {
119
+ return { type: 'msgError', data: packet }; // Error
120
+ }
121
+ }
122
+
123
+ wsQuoteCreateSession({ session }) {
124
+ return this.formatWSPacket({ packet: { m: 'quote_create_session', p: [session] } });
125
+ }
126
+
127
+ wsCreateChartSession({ chartSession }) {
128
+ return this.formatWSPacket({ packet: { m: 'chart_create_session', p: [chartSession, ''] } });
129
+ }
130
+
131
+ setFieldsQuote({ session }) {
132
+ return this.formatWSPacket({ packet: { m: 'quote_set_fields', p: [session, 'lp'] } });
133
+ }
134
+
135
+ setFieldsChart({ session }) {
136
+ return this.formatWSPacket({
137
+ packet: {
138
+ m: 'quote_set_fields',
139
+ p: [
140
+ session,
141
+ 'ch',
142
+ 'chp',
143
+ 'current_session',
144
+ 'description',
145
+ // 'local_description',
146
+ // 'language',
147
+ 'exchange',
148
+ // 'format',
149
+ // 'fractional',
150
+ 'is_tradable',
151
+ 'lp',
152
+ 'lp_time',
153
+ // 'minmov',
154
+ // 'minmove2',
155
+ 'original_name',
156
+ // 'pricescale',
157
+ 'pro_name',
158
+ 'short_name',
159
+ 'type',
160
+ // 'update_mode',
161
+ 'volume',
162
+ 'ask',
163
+ 'bid',
164
+ 'high_price',
165
+ 'low_price',
166
+ 'open_price',
167
+ 'prev_close_price',
168
+ 'currency_code',
169
+ // 'rch',
170
+ // 'rchp',
171
+ // 'rtc',
172
+ 'status',
173
+ ],
174
+ },
175
+ });
176
+ }
177
+
178
+ quoteAddSymbols({ session, symbolIds }) {
179
+ return this.formatWSPacket({ packet: { m: 'quote_add_symbols', p: [session, ...symbolIds] } });
180
+ }
181
+
182
+ quoteRemoveSymbols({ session, symbolId }) {
183
+ return this.formatWSPacket({ packet: { m: 'quote_remove_symbols', p: [session, symbolId] } });
184
+ }
185
+
186
+ switchTimezone({ chartSession, tz = 'Etc/UTC' }) {
187
+ return this.formatWSPacket({ packet: { m: 'switch_timezone', p: [chartSession, tz] } });
188
+ }
189
+
190
+ resolveSymbol({ chartSession, rSymbolId, symbolId }) {
191
+ return this.formatWSPacket({
192
+ packet: {
193
+ m: 'resolve_symbol',
194
+ p: [chartSession, rSymbolId, '={"symbol":"' + symbolId + '","adjustment":"splits","session":"extended"}'],
195
+ },
196
+ });
197
+ }
198
+
199
+ createSeries({ chartSession, id = 1, interval = '60', total_candle = 1000 }) {
200
+ return this.formatWSPacket({
201
+ packet: { m: 'create_series', p: [chartSession, 's' + id, 's' + id, 'symbol_1', interval, total_candle] },
202
+ });
203
+ }
204
+
205
+ modifySeries({ chartSession, rSymbolId, symbolId }) {
206
+ return this.formatWSPacket({
207
+ packet: {
208
+ m: 'resolve_symbol',
209
+ p: [chartSession, 'symbol_' + id, '={"symbol":"' + symbolId + '","adjustment":"splits","session":"extended"}'],
210
+ },
211
+ });
212
+ }
213
+
214
+ createPong({ value }) {
215
+ return this.formatWSPacket({ packet: '~h~' + value });
216
+ }
217
+ }
package/lib/utils.js ADDED
@@ -0,0 +1,39 @@
1
+ import https from 'https';
2
+
3
+ export class Utils {
4
+ pause(time = 1000) {
5
+ return new Promise((resolve) => {
6
+ setTimeout(resolve, time);
7
+ });
8
+ }
9
+
10
+ request(options = {}, raw = false, content = '') {
11
+ return new Promise((cb, err) => {
12
+ const req = https.request(options, (res) => {
13
+ let data = '';
14
+ res.on('data', (c) => {
15
+ data += c;
16
+ });
17
+ res.on('end', () => {
18
+ if (raw) {
19
+ cb({ data, cookies: res.headers['set-cookie'] });
20
+ return;
21
+ }
22
+
23
+ try {
24
+ data = JSON.parse(data);
25
+ } catch (error) {
26
+ console.log(data);
27
+ err(new Error("Can't parse server response"));
28
+ return;
29
+ }
30
+
31
+ cb({ data, cookies: res.headers['set-cookie'] });
32
+ });
33
+ });
34
+
35
+ req.on('error', err);
36
+ req.end(content);
37
+ });
38
+ }
39
+ }
package/old.js ADDED
@@ -0,0 +1,141 @@
1
+ 'use strict';
2
+
3
+ process.title = 'socket_client';
4
+
5
+ const urlWS = 'wss://data.tradingview.com/socket.io/websocket';
6
+
7
+ const login = 'sulimenko@ptfin.kz';
8
+ const pass = '7n8zGZ8v27pH';
9
+ const token = '';
10
+ const interval = '5';
11
+ const total_candle = 100;
12
+
13
+ const stop = async () => {
14
+ const closed = new Promise((resolve) => {
15
+ setTimeout(() => {
16
+ resolve(console.log('exit'));
17
+ }, 1000);
18
+ });
19
+
20
+ for (const sessionKey of sessions.values.keys()) {
21
+ sessions.values.delete(sessionKey);
22
+ console.log('session clear: ', sessionKey);
23
+ }
24
+ socket.close();
25
+ await closed;
26
+ process.exit(1);
27
+ };
28
+
29
+ function changeWSSymbol({ key, chartkey, symbolId }) {
30
+ const s = sessions.get({ key });
31
+ const c = sessions.get({ key: chartkey });
32
+ const queue = [];
33
+
34
+ // console.log(s, symbolId, id, c, chartkey, sessions);
35
+ if (s.symbolId) queue.push(tv.removeSymbols({ session: s.main, symbolId: s.symbolId }));
36
+ queue.push(tv.addSymbols({ session: s.main, symbolId }));
37
+ queue.push(tv.resolveSymbol({ chartSession: c.main, id, symbolId }));
38
+
39
+ queue.forEach((each) => {
40
+ console.log(each);
41
+ socket.send(each);
42
+ });
43
+ id++;
44
+ sessions.set({ key, val: { main: key, symbolId } });
45
+ sessions.set({ key: chartkey, val: { main: chartkey, symbolId } });
46
+ }
47
+
48
+ (async () => {
49
+
50
+ // const data = await tv.getSymbol({ symbol: 'TSLA', type: 'stock' }); // NASDAQ:TSLA
51
+ // const data = await tv.getSymbol({ symbol: 'MRNA', type: 'stock' }); // NASDAQ:MRNA
52
+ const data = await tv.getSymbol({ symbol: 'BTCUSDT', type: 'crypto' });
53
+ // console.log('symbol: ', data);
54
+
55
+ const symbolId = tv.getSymbolId({ data });
56
+ console.log(symbolId);
57
+
58
+ socket = new WebSocket(urlWS, { origin: 'https://data.tradingview.com' });
59
+ // // const socket = new WebSocket('wss://data.tradingview.com/socket.io/websocket?&type=chart', { origin: 'https://s.tradingview.com' });
60
+
61
+ const sessionKey = tv.createSession({ startsWith: 'qs_' });
62
+ const chartSessionKey = tv.createSession({ startsWith: 'cs_' });
63
+ sessions.set({ key: sessionKey, val: { main: sessionKey } });
64
+ sessions.set({ key: chartSessionKey, val: { main: chartSessionKey } });
65
+ let session = sessions.get({ key: sessionKey });
66
+ let chartSession = sessions.get({ key: chartSessionKey });
67
+ // console.log(session);
68
+
69
+ socket.on('open', (e) => {
70
+ console.log('open');
71
+ socket.send(auth());
72
+
73
+ socket.send(tv.wsCreateChartSession({ chartSession: chartSession.main }));
74
+ socket.send(tv.switchTimezone({ chartSession: chartSession.main, tz: 'Etc/UTC' }));
75
+ socket.send(tv.wsCreateSession({ session: session.main }));
76
+ // socket.send(tv.resolveSymbol({ chartSession, id: 1, symbolId }));
77
+ changeWSSymbol({ key: session.main, chartkey: chartSession.main, symbolId });
78
+
79
+ socket.send(tv.setFieldsChart({ session: session.main }));
80
+ socket.send(tv.createSeries({ chartSession: chartSession.main, id: 1, interval, total_candle }));
81
+
82
+ // setTimeout(() => {
83
+ // addWSSymbol({ key: session.main, symbolId: 'NASDAQ:TSLA' });
84
+ setTimeout(() => {
85
+ changeWSSymbol({ key: session.main, chartkey: chartSession.main, symbolId: 'NASDAQ:TSLA' });
86
+ }, 10000);
87
+ // }, 10000);
88
+ });
89
+
90
+ socket.on('message', (raw) => {
91
+ const response = tv.parsePacket({ readyState: socket.readyState, str: raw });
92
+ // console.log(response, response === undefined);
93
+ response.forEach((packet) => {
94
+ // console.log(packet);
95
+ if (packet === undefined) {
96
+ console.log('undefined: ', raw.toString());
97
+ } else {
98
+ if (packet.type === 'ping') {
99
+ // console.log('pong', packet);
100
+ socket.send(tv.createPong({ value: packet.data }));
101
+ } else if (packet.type === 'protocol_error') {
102
+ console.log('protocol_error', packet);
103
+ socket.close();
104
+ } else if (packet.type === 'qsd') {
105
+ session = sessions.get({ key: packet.data[0] });
106
+ // console.log(packet.data, session, sessions);
107
+ const send = packet.data[1].v;
108
+ send.symbol = session.symbolId;
109
+ console.log(JSON.stringify([packet.type, send]));
110
+ } else if (['du', 'timescale_update'].includes(packet.type)) {
111
+ session = sessions.get({ key: packet.data[0] });
112
+ // console.log(packet.data, session, sessions);
113
+ const arr = [];
114
+ for (var key in packet.data[1].s1.s) {
115
+ const send = {
116
+ symbol: session.symbolId,
117
+ end: packet.data[1].s1.s[key + 1] !== undefined ? packet.data[1].s1.s[key + 1].v[0] : packet.data[1].s1.lbs.bar_close_time,
118
+ };
119
+ // console.log(key, packet.data[1].s1.s);
120
+ [send.start, send.open, send.low, send.high, send.close, send.passed] = packet.data[1].s1.s[key].v;
121
+ // console.log(send);
122
+ arr.push(send);
123
+ }
124
+ // [send.start, send.open, send.low, send.high, send.close, send.passed] = packet.data[1].s1.s.v;
125
+ console.log(JSON.stringify([packet.type, arr]));
126
+ } else {
127
+ console.log('error', raw.toString());
128
+ }
129
+ // else {
130
+ // console.log('received: %s', raw);
131
+ // }
132
+ }
133
+ });
134
+ });
135
+ // // setTimeout(async () => {
136
+ // // console.log('exit');
137
+ // // }, 3000);
138
+
139
+ process.on('SIGINT', stop);
140
+ process.on('SIGTERM', stop);
141
+ })();
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "market-data-tradingview-ws",
3
+ "version": "0.0.1",
4
+ "description": "marketData from Tradingview ws",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "author": "sulimenkoas@gmail.com",
11
+ "license": "MIT",
12
+ "dependencies": {
13
+ "ws": "^8.13.0"
14
+ }
15
+ }
package/server.js ADDED
@@ -0,0 +1,91 @@
1
+ 'use strict';
2
+
3
+ process.title = 'marketDataClient';
4
+
5
+ import { Client } from './lib/client.js';
6
+ import { Utils } from './lib/utils.js';
7
+ const u = new Utils();
8
+
9
+ const url = 'wss://data.tradingview.com/socket.io/websocket';
10
+ const options = { origin: 'https://data.tradingview.com' };
11
+
12
+ const login = 'sulimenko@ptfin.kz';
13
+ const pass = '7n8zGZ8v27pH';
14
+
15
+ const interval = '5';
16
+ const total_candle = 100;
17
+
18
+ const marketData = new Client();
19
+
20
+ const clients = new Map();
21
+ const symbolQuotes = new Map();
22
+
23
+ const stop = async () => {
24
+ const closed = new Promise((resolve) => {
25
+ setTimeout(() => {
26
+ resolve(console.log('exit'));
27
+ }, 1000);
28
+ });
29
+
30
+ // for (const sessionKey of marketData.getSessionKeys()) {
31
+ // let data = marketData.getSession({ key: sessionKey });
32
+ // console.log('session clear: ', sessionKey, data);
33
+ // }
34
+ marketData.close();
35
+ await closed;
36
+ console.log(clients, symbolQuotes);
37
+ process.exit(1);
38
+ };
39
+
40
+ const result = ({ packet }) => {
41
+ let data = symbolQuotes.get(packet.symbol);
42
+ if (!data) data = {};
43
+ Object.keys(packet).forEach((key) => {
44
+ // console.log(key, data, packet);
45
+ data[key] = packet[key];
46
+ });
47
+ symbolQuotes.set(packet.symbol, data);
48
+
49
+ clients.forEach((each) => {
50
+ if (each.quote.includes(packet.symbol)) {
51
+ each.client({ acc: each.acc, packet });
52
+ }
53
+ });
54
+ };
55
+
56
+ // function changeWSSymbol({ key, chartkey, symbolId }) {
57
+ // const s = sessions.get({ key });
58
+ // const c = sessions.get({ key: chartkey });
59
+ // const queue = [];
60
+
61
+ // // console.log(s, symbolId, id, c, chartkey, sessions);
62
+ // if (s.symbolId) queue.push(tv.removeSymbols({ session: s.main, symbolId: s.symbolId }));
63
+ // queue.push(tv.addSymbols({ session: s.main, symbolId }));
64
+ // queue.push(tv.resolveSymbol({ chartSession: c.main, id, symbolId }));
65
+
66
+ // queue.forEach((each) => {
67
+ // console.log(each);
68
+ // socket.send(each);
69
+ // });
70
+ // id++;
71
+ // sessions.set({ key, val: { main: key, symbolId } });
72
+ // sessions.set({ key: chartkey, val: { main: chartkey, symbolId } });
73
+ // }
74
+
75
+ (async () => {
76
+ clients.set('123', { acc: '123', quote: ['NASDAQ:TSLA', 'NASDAQ:META'], client: ({ acc, packet }) => console.log(acc, packet) });
77
+ clients.set('U444', { acc: 'U444', quote: ['NASDAQ:MRNA', 'NASDAQ:LI'], client: ({ acc, packet }) => console.log(acc, packet) });
78
+
79
+ const status = await marketData.connect({ url, options, login, pass, result });
80
+ console.log(status);
81
+ // await u.pause(2000);
82
+ marketData.createSession({ type: 'chart' });
83
+ marketData.createSession({ type: 'quote' });
84
+
85
+ clients.forEach((each) => {
86
+ marketData.addQuoteSymbols({ symbolIds: each.quote });
87
+ });
88
+
89
+ process.on('SIGINT', stop);
90
+ process.on('SIGTERM', stop);
91
+ })();