market-data-tradingview-ws 0.0.12 → 0.0.13

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/client.js CHANGED
@@ -13,10 +13,13 @@ const periods = {
13
13
  3600: '60',
14
14
  14400: '240',
15
15
  86400: '1D',
16
+ 604800: '1W',
17
+ 2592000: '1M',
16
18
  };
17
19
 
20
+ let ws = null;
21
+
18
22
  module.exports = class Client {
19
- #ws;
20
23
  #charts = {
21
24
  values: {},
22
25
  set({ key, data }) {
@@ -29,6 +32,7 @@ module.exports = class Client {
29
32
  frame: data.frame,
30
33
  i: data.i,
31
34
  deleted: data.deleted || false,
35
+ limit: data.limit || 1500,
32
36
  };
33
37
  }
34
38
  },
@@ -84,17 +88,29 @@ module.exports = class Client {
84
88
  if (index !== -1) arr.splice(index, 1);
85
89
  },
86
90
  };
91
+ #symbols = {
92
+ values: {},
93
+ max: 1,
94
+ getSymbol({ key, symbol }) {
95
+ // let data = this.values[symbol];
96
+ // if (data === undefined) data = this.set({ key, symbol });
97
+ // return data;
98
+ const symbolKey = 'sds_sym_' + this.max++;
99
+ ws.send(tv.resolveSymbol({ chartSession: key, symbolKey, symbol }));
100
+ this.values[symbol] = { key: symbolKey };
101
+ return this.values[symbol];
102
+ },
103
+ };
87
104
 
88
- // #resolved;
89
105
  #token = null;
90
- #maxSymbolKey = 1;
91
106
 
92
107
  constructor() {
93
108
  // this.#resolved = new Map();
94
109
  }
95
110
 
96
- close() {
97
- this.#ws.close();
111
+ async close() {
112
+ // token delete !!!
113
+ ws.close();
98
114
  }
99
115
 
100
116
  getAll() {
@@ -130,23 +146,31 @@ module.exports = class Client {
130
146
  });
131
147
  }
132
148
 
133
- async connect({ url, options, login, pass, result }) {
134
- this.#token = await this.getToken({ login, pass });
135
- // console.log(this.#token);
149
+ async connect({ url, options, login, pass, result, token }) {
150
+ this.#token = token || await this.getToken({ login, pass });
151
+
136
152
  if (this.#token.length > 10) {
137
153
  return new Promise((resolv, reject) => {
138
- this.#ws = new WebSocket(url, options);
154
+ url += '?from=chart%2FKq8EfKQU%2F';
155
+ const date = new Date();
156
+ url += '&date=' + date.getFullYear() + '_' + String(date.getMonth() + 1).padStart(2, '0') + '_' + String(date.getDate()).padStart(2, '0') + '-11_25';
157
+ url += '&type=chart';
158
+ ws = new WebSocket(url, options);
159
+
160
+ const originalSend = ws.send;
161
+ ws.send = function(data) {
162
+ // console.log('Message sent:', data);
163
+ originalSend.apply(ws, arguments);
164
+ };
139
165
 
140
- this.#ws.onclose = () => console.log('disconnected');
166
+ ws.onclose = () => console.log('disconnected');
141
167
 
142
- this.#ws.onerror = (error) => reject(console.error('error: ', error));
143
- this.#ws.onopen = () => {
144
- this.#ws.send(this.auth(this.#token));
145
- this.#ws.send(tv.setLocaleRu());
168
+ ws.onerror = (error) => reject(console.error('error: ', error));
169
+ ws.onopen = () => {
170
+ ws.send(this.auth(this.#token));
171
+ ws.send(tv.setLocaleRu());
146
172
 
147
- // const chartKey = this.createChartSession();
148
173
  const quoteKey = this.createQuoteSmallSession();
149
- // this.addQuoteSymbols({ symbols: ['NASDAQ:PYPL'] });
150
174
 
151
175
  this.messageListner({ result });
152
176
  resolv('open');
@@ -159,24 +183,24 @@ module.exports = class Client {
159
183
  createQuoteSmallSession() {
160
184
  const key = tv.createSession({ startsWith: 'qs_' });
161
185
  this.#quotes.set({ key, data: { id: key, type: 'small', symbols: [] } });
162
- this.#ws.send(tv.quoteCreateSession({ session: key }));
163
- this.#ws.send(tv.setFieldsSmall({ session: key }));
164
- // this.#ws.send(tv.setFields({ session: key }));
186
+ ws.send(tv.quoteCreateSession({ session: key }));
187
+ ws.send(tv.setFieldsSmall({ session: key }));
188
+ // ws.send(tv.setFields({ session: key }));
165
189
  return key;
166
190
  }
167
191
 
168
192
  createQuoteFullSession() {
169
193
  const key = tv.createSession({ startsWith: 'qs_' });
170
194
  this.#quotes.set({ key, data: { id: key, type: 'full', symbols: [] } });
171
- this.#ws.send(tv.quoteCreateSession({ session: key }));
195
+ ws.send(tv.quoteCreateSession({ session: key }));
172
196
  return key;
173
197
  }
174
198
 
175
199
  createChartSession() {
176
200
  const key = tv.createSession({ startsWith: 'cs_' });
177
201
  this.#charts.set({ key, data: { id: key, symbol: '', period: 0, symbolKey: '', frame: '', i: '', deleted: false } });
178
- this.#ws.send(tv.chartCreateSession({ chartSession: key }));
179
- this.#ws.send(tv.switchTimezone({ chartSession: key, tz: 'Etc/UTC' }));
202
+ ws.send(tv.chartCreateSession({ chartSession: key }));
203
+ ws.send(tv.switchTimezone({ chartSession: key, tz: 'Etc/UTC' }));
180
204
  return key;
181
205
  }
182
206
 
@@ -189,9 +213,8 @@ module.exports = class Client {
189
213
  result.exist.push(symbol);
190
214
  } else {
191
215
  key = this.#quotes.add({ symbol });
192
- // console.log(key, symbol);
193
- this.#ws.send(tv.quoteAddSymbol({ session: key, symbol }));
194
- // this.#ws.send(tv.quoteFastSymbol({ session: key, symbol }));
216
+ ws.send(tv.quoteAddSymbol({ session: key, symbol }));
217
+ // ws.send(tv.quoteFastSymbol({ session: key, symbol }));
195
218
  result.add.push(symbol);
196
219
  }
197
220
  });
@@ -202,39 +225,31 @@ module.exports = class Client {
202
225
  const key = this.#quotes.getBySymbol({ symbol });
203
226
  if (!key) return 'unlisted';
204
227
  this.#quotes.delete({ key, symbol });
205
- this.#ws.send(tv.quoteRemoveSymbols({ session: key, symbol }));
228
+ ws.send(tv.quoteRemoveSymbols({ session: key, symbol }));
206
229
  return 'delete';
207
230
  }
208
231
 
209
- resolveSymbol({ key, symbol }) {
210
- const symbolKey = 'sds_sym_' + this.#maxSymbolKey++;
211
- this.#ws.send(tv.resolveSymbol({ chartSession: key, symbolKey, symbol }));
212
- return symbolKey;
213
- }
214
-
215
232
  addChartSymbol({ symbol, period, limit }) {
216
233
  let key = this.#charts.getBySymbolPeriod({ symbol, period });
217
234
  if (key) {
218
- console.warn('addChartSymbol exist');
235
+ console.warn('addChartSymbol exist:', key, symbol, period);
219
236
  return 'exist';
220
237
  }
221
-
222
238
  // console.warn('modules addChartSymbol1', symbol, period, limit, key);
223
- const exist = this.#charts.getDeleted();
224
- if (exist !== null) return this.updateChartSymbol({ symbol, period, limit, last: { symbol: exist.symbol, period: parseInt(exist.period) }});
239
+ const deleted = this.#charts.getDeleted();
240
+ if (deleted !== null && deleted.limit >= limit) return this.updateChartSymbol({ symbol, period, limit, last: { symbol: deleted.symbol, period: parseInt(deleted.period) }});
225
241
 
226
242
  key = this.createChartSession();
227
243
  const data = this.#charts.get({ key });
228
244
 
229
- data.symbolKey = this.resolveSymbol({ key, symbol });
245
+ data.symbolKey = this.#symbols.getSymbol({ key, symbol }).key;
230
246
  data.symbol = symbol;
231
247
  data.period = period;
232
248
  data.frame = 'sds_' + Object.keys(this.#charts.values).length;
233
249
  data.i = 's' + 1;
250
+ data.limit = limit;
234
251
 
235
- // this.#ws.send(tv.resolveSymbol({ chartSession: key, symbolKey: data.symbolKey, symbol }));
236
- // this.#resolved.set(symbol, { key: data.symbolKey });
237
- this.#ws.send(
252
+ ws.send(
238
253
  tv.createSeries({
239
254
  chartSession: key,
240
255
  frame: data.frame,
@@ -244,49 +259,56 @@ module.exports = class Client {
244
259
  limit,
245
260
  }),
246
261
  );
247
- // console.log('addChartSymbol4', periods[period], data);
262
+ // console.warn('addChartSymbol4', periods[period], data);
248
263
  this.#charts.set({ key, data });
249
-
250
264
  return 'add';
251
265
  }
252
266
 
253
267
  updateChartSymbol({ symbol, period, limit, last }) {
254
- // period = parseInt(period);
255
- // last.period = parseInt(last.period);
256
268
  const key = this.#charts.getBySymbolPeriod({ symbol: last.symbol, period: last.period });
257
269
  const data = this.#charts.get({ key });
258
270
 
259
271
  // console.warn('modules updateChartSymbol 1: ', symbol, period, limit, last, data);
260
-
261
- const alreadyKey = this.#charts.getBySymbolPeriod({ symbol, period })
262
- if (alreadyKey) {
263
- // console.warn('updateChartSymbol exist: ', alreadyKey);
264
- this.#charts.delete({ key });
265
- console.warn('updateChartSymbol exist');
266
- return 'exist';
267
- }
272
+ // const alreadyKey = this.#charts.getBySymbolPeriod({ symbol, period })
273
+ // if (alreadyKey) {
274
+ // // console.warn('updateChartSymbol exist: ', alreadyKey);
275
+ // this.#charts.delete({ key });
276
+ // // console.warn('updateChartSymbol exist');
277
+ // return 'exist';
278
+ // }
268
279
 
269
- data.symbolKey = this.resolveSymbol({ key, symbol });
280
+ data.symbolKey = this.#symbols.getSymbol({ key, symbol }).key;
270
281
  data.symbol = symbol;
271
282
  data.period = period;
272
283
  data.i = 's' + (parseInt(data.i.replace(/[^0-9]/g, '')) + 1);
273
- this.#ws.send(
284
+
285
+ ws.send(
274
286
  tv.modifySeries({
275
287
  chartSession: key,
276
288
  frame: data.frame,
277
289
  increment: data.i,
278
290
  symbolKey: data.symbolKey,
279
291
  interval: periods[period],
280
- limit,
281
292
  }),
282
293
  );
283
294
  this.#charts.set({ key, data });
295
+ if (data.limit < limit) {
296
+ ws.send(tv.moreData({ chartSession: key, frame: data.frame, add: limit - data.limit }));
297
+ data.limit = limit;
298
+ }
284
299
  return 'update';
285
300
  }
286
301
 
302
+ deleteChartSymbol({ symbol, period }) {
303
+ let key = this.#charts.getBySymbolPeriod({ symbol, period });
304
+ if (!key) return void console.warn('deleteChartSymbol empty key');
305
+ this.#charts.delete({ key });
306
+ return void console.log('deleteChartSymbol: ', key);
307
+ }
308
+
287
309
  messageListner({ result }) {
288
- this.#ws.on('message', (raw) => {
289
- if (this.#ws.readyState !== this.#ws.OPEN) return;
310
+ ws.on('message', (raw) => {
311
+ if (ws.readyState !== ws.OPEN) return;
290
312
 
291
313
  // console.log('raw: ', JSON.stringify(raw.toString()));
292
314
  let session = '';
@@ -296,13 +318,9 @@ module.exports = class Client {
296
318
  if (packet === undefined) {
297
319
  console.warn('undefined: ', raw.toString());
298
320
  } else {
299
- // eslint-disable-next-line no-lonely-if
300
321
  if (packet.type === 'ping') {
301
322
  // console.info('pong', packet);
302
- this.#ws.send(tv.createPong({ value: packet.data }));
303
- // } else if (packet.type === 'protocol_error') {
304
- // console.warn('protocol_error', packet);
305
- // this.close();
323
+ ws.send(tv.createPong({ value: packet.data }));
306
324
  } else if (packet.type === 'qsd') {
307
325
  send = packet.data[1].v;
308
326
  name = send.bid === undefined && send.ask === undefined ? 'data' : 'levelI';
@@ -335,12 +353,12 @@ module.exports = class Client {
335
353
  } else if (['series', 'symbol', 'quote', 'session'].includes(packet.type)) {
336
354
  // console.info(packet);
337
355
  } else {
338
- console.warn('error', raw.toString());
356
+ // console.error('error', raw.toString());
339
357
  result('error', raw.toString())
340
358
  }
341
359
  }
342
- name = null;
343
- send = null;
360
+ // name = null;
361
+ // send = null;
344
362
  });
345
363
  });
346
364
  }
@@ -35,8 +35,7 @@ class TradingView {
35
35
  // }
36
36
 
37
37
  // await utils.pause();
38
- // old return 'eyJhbGciOiJSUzUxMiIsImtpZCI6IkdaeFUiLCJ0eXAiOiJKV1QifQ.eyJ1c2VyX2lkIjoxMjI1ODcxMiwiZXhwIjoxNjkwNzkzMjIwLCJpYXQiOjE2OTA3Nzg4MjAsInBsYW4iOiJwcm9fcHJlbWl1bSIsImV4dF9ob3VycyI6MSwicGVybSI6IiIsInN0dWR5X3Blcm0iOiJ0di1jaGFydF9wYXR0ZXJucyx0di1jaGFydHBhdHRlcm5zLHR2LXByb3N0dWRpZXMsdHYtdm9sdW1lYnlwcmljZSIsIm1heF9zdHVkaWVzIjoyNSwibWF4X2Z1bmRhbWVudGFscyI6MCwibWF4X2NoYXJ0cyI6OCwibWF4X2FjdGl2ZV9hbGVydHMiOjQwMCwibWF4X3N0dWR5X29uX3N0dWR5IjoyNCwibWF4X2FjdGl2ZV9wcmltaXRpdmVfYWxlcnRzIjo0MDAsIm1heF9hY3RpdmVfY29tcGxleF9hbGVydHMiOjQwMCwibWF4X2Nvbm5lY3Rpb25zIjo1MH0.pZQgM_oTZMnm1Qb4qBf6CfM9dHKltp2T3O2g_VVoK9l66UngEL8mLdeH7-ZpUZ8Y50rV5yr0ND8WRPsRH2w2izk_SNMD63p6GJzXXGPvILgirXW3SFa7HmaHv8Xp6SPhQTWb-ahyv_2GUIueKTvHWBNF5-eBnqYeoXQeWkRFsLA';
39
- return 'eyJhbGciOiJSUzUxMiIsImtpZCI6IkdaeFUiLCJ0eXAiOiJKV1QifQ.eyJ1c2VyX2lkIjoxMjI1ODcxMiwiZXhwIjoxNzA1OTE3OTE1LCJpYXQiOjE3MDU5MDM1MTUsInBsYW4iOiJwcm9fcHJlbWl1bSIsImV4dF9ob3VycyI6MSwicGVybSI6IiIsInN0dWR5X3Blcm0iOiJ0di1wcm9zdHVkaWVzLHR2LWNoYXJ0X3BhdHRlcm5zLHR2LXZvbHVtZWJ5cHJpY2UsdHYtY2hhcnRwYXR0ZXJucyIsIm1heF9zdHVkaWVzIjoyNSwibWF4X2Z1bmRhbWVudGFscyI6MTAsIm1heF9jaGFydHMiOjgsIm1heF9hY3RpdmVfYWxlcnRzIjo0MDAsIm1heF9zdHVkeV9vbl9zdHVkeSI6MjQsIm1heF9vdmVyYWxsX2FsZXJ0cyI6MjAwMCwibWF4X2FjdGl2ZV9wcmltaXRpdmVfYWxlcnRzIjo0MDAsIm1heF9hY3RpdmVfY29tcGxleF9hbGVydHMiOjQwMCwibWF4X2Nvbm5lY3Rpb25zIjo1MH0.Zoe1DAU3Fn2XpNNvI7uYK0JGHEsNs_OjTqBsnj8vsqWWeDDaOFPVO5m_DLuaUaSFZ4w3diQtgqfeovyPzzUCFDooGEF9FRypY9-zTjGbV0pbQajx-a8X3j79qxvLWe7VYg7cx5RQJGBoN7CGIPzrdpvNvVEYGb_QqXOPy_-F1BE';
38
+ return 'eyJhbGciOiJSUzUxMiIsImtpZCI6IkdaeFUiLCJ0eXAiOiJKV1QifQ.eyJ1c2VyX2lkIjoxMjI1ODcxMiwiZXhwIjoxNzI0OTI1MjkyLCJpYXQiOjE3MjQ5MTA4OTIsInBsYW4iOiJwcm9fcHJlbWl1bSIsImV4dF9ob3VycyI6MSwicGVybSI6InVzLXN0b2NrcyxuYXNkYXFfZ2lkcyxvdGMsbnlzZSxuYXNkYXEsYW1leCIsInN0dWR5X3Blcm0iOiJ0di1jaGFydHBhdHRlcm5zLHR2LXByb3N0dWRpZXMsdHYtY2hhcnRfcGF0dGVybnMsdHYtdm9sdW1lYnlwcmljZSIsIm1heF9zdHVkaWVzIjoyNSwibWF4X2Z1bmRhbWVudGFscyI6MTAsIm1heF9jaGFydHMiOjgsIm1heF9hY3RpdmVfYWxlcnRzIjo0MDAsIm1heF9zdHVkeV9vbl9zdHVkeSI6MjQsImZpZWxkc19wZXJtaXNzaW9ucyI6WyJyZWZib25kcyJdLCJtYXhfb3ZlcmFsbF9hbGVydHMiOjIwMDAsIm1heF9hY3RpdmVfcHJpbWl0aXZlX2FsZXJ0cyI6NDAwLCJtYXhfYWN0aXZlX2NvbXBsZXhfYWxlcnRzIjo0MDAsIm1heF9jb25uZWN0aW9ucyI6NTB9.UT2AdPBEAWk6HJEa6isX4gjVqlfThn8bgOVl3Xa36U36Qifg5xXz9Va8q7DWSY3Smaap2wX4cBF4UQXv1t66Q0TQvFudLuvA2dnetBAHYZSOJIi2PGdG1KuMaCRshUuuH9mxgw_xPGITAuQsbBPZJLTOxq5pQN05pZnedC7SaMs';
40
39
  }
41
40
 
42
41
  async getSymbol({ symbol, type }) {
@@ -60,9 +59,7 @@ class TradingView {
60
59
 
61
60
  createSession({ startsWith }) {
62
61
  let session = startsWith;
63
- while (session.length < 12) {
64
- session += letters[Math.floor(Math.random() * letters.length)];
65
- }
62
+ while (session.length < 12) session += letters[Math.floor(Math.random() * letters.length)];
66
63
  return session;
67
64
  }
68
65
 
@@ -269,10 +266,10 @@ class TradingView {
269
266
  // symbolKey - id запрошенного тиккера
270
267
  // frame - рамка или окно для данной серии
271
268
  // increment - инкрементируемый номер изменений запрашиваемого графика в данном frame (таймефрейм)
272
- createSeries({ chartSession, frame = 'sds_1', increment = 's1', symbolKey, interval = '60', limit = 1000 }) {
269
+ createSeries({ chartSession, frame = 'sds_1', increment = 's1', symbolKey, period = '60', limit = 1000 }) {
273
270
  // console.warn('createSeries', chartSession, frame, increment, symbolKey, interval, limit);
274
271
  return this.formatWSPacket({
275
- packet: { m: 'create_series', p: [chartSession, frame, increment, symbolKey, interval, limit] },
272
+ packet: { m: 'create_series', p: [chartSession, frame, increment, symbolKey, period, limit] },
276
273
  });
277
274
  }
278
275
 
@@ -287,13 +284,22 @@ class TradingView {
287
284
  return this.formatWSPacket({ packet: { m: 'remove_study', p: [ session, st ] } });
288
285
  }
289
286
 
290
- modifySeries({ chartSession, frame = 'sds_1', increment = 's1', symbolKey, interval = '60', limit = 1000 }) {
287
+ modifySeries({ chartSession, frame = 'sds_1', increment = 's1', symbolKey, interval = '60' }) {
291
288
  // console.warn('modify_series', chartSession, frame, increment, symbolKey, interval, limit);
292
289
  return this.formatWSPacket({
293
290
  packet: { m: 'modify_series', p: [chartSession, frame, increment, symbolKey, interval] },
294
291
  });
295
292
  }
296
293
 
294
+ moreData({ chartSession, frame, add }) {
295
+ return this.formatWSPacket({ packet: { m: 'request_more_data', p: [chartSession, frame, add] } });
296
+ }
297
+
298
+ moreTickmark({chartSession, frame, add}) {
299
+ // "m":"request_more_tickmarks","p":["cs_lslcBHYaqGTT","sds_1",10]
300
+ return this.formatWSPacket({ packet: { m: 'request_more_tickmarks', p: [chartSession, frame, add] } });
301
+ }
302
+
297
303
  createPong({ value }) {
298
304
  return this.formatWSPacket({ packet: '~h~' + value });
299
305
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "market-data-tradingview-ws",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "marketData from Tradingview ws",
5
5
  "main": "index.js",
6
6
  "scripts": {