@mathieuc/tradingview 3.5.1 → 4.0.0-beta.0

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.
Files changed (120) hide show
  1. package/README.md +112 -51
  2. package/dist/chart/chart-session.d.ts +114 -0
  3. package/dist/chart/chart-session.js +339 -0
  4. package/dist/chart/graphics.d.ts +129 -0
  5. package/dist/chart/graphics.js +153 -0
  6. package/dist/chart/index.d.ts +11 -0
  7. package/dist/chart/index.js +6 -0
  8. package/dist/chart/strategy.d.ts +100 -0
  9. package/dist/chart/strategy.js +51 -0
  10. package/dist/chart/study.d.ts +60 -0
  11. package/dist/chart/study.js +171 -0
  12. package/dist/chart/timeframes.d.ts +7 -0
  13. package/dist/chart/timeframes.js +22 -0
  14. package/dist/chart/types.d.ts +105 -0
  15. package/dist/chart/types.js +9 -0
  16. package/dist/client/client.d.ts +89 -0
  17. package/dist/client/client.js +254 -0
  18. package/dist/client/index.d.ts +4 -0
  19. package/dist/client/index.js +2 -0
  20. package/dist/client/transport.d.ts +27 -0
  21. package/dist/client/transport.js +38 -0
  22. package/dist/data/candles.d.ts +40 -0
  23. package/dist/data/candles.js +101 -0
  24. package/dist/data/history.d.ts +61 -0
  25. package/dist/data/history.js +101 -0
  26. package/dist/data/index.d.ts +28 -0
  27. package/dist/data/index.js +15 -0
  28. package/dist/data/indicators.d.ts +54 -0
  29. package/dist/data/indicators.js +139 -0
  30. package/dist/data/operation.d.ts +71 -0
  31. package/dist/data/operation.js +205 -0
  32. package/dist/data/provider.d.ts +23 -0
  33. package/dist/data/provider.js +11 -0
  34. package/dist/data/quotes.d.ts +33 -0
  35. package/dist/data/quotes.js +117 -0
  36. package/dist/data/symbols.d.ts +9 -0
  37. package/dist/data/symbols.js +19 -0
  38. package/dist/errors.d.ts +53 -0
  39. package/dist/errors.js +24 -0
  40. package/dist/events.d.ts +36 -0
  41. package/dist/events.js +70 -0
  42. package/dist/http/account.d.ts +47 -0
  43. package/dist/http/account.js +127 -0
  44. package/dist/http/index.d.ts +11 -0
  45. package/dist/http/index.js +5 -0
  46. package/dist/http/indicators.d.ts +37 -0
  47. package/dist/http/indicators.js +144 -0
  48. package/dist/http/layouts.d.ts +36 -0
  49. package/dist/http/layouts.js +24 -0
  50. package/dist/http/market.d.ts +45 -0
  51. package/dist/http/market.js +59 -0
  52. package/dist/http/pine-permissions.d.ts +29 -0
  53. package/dist/http/pine-permissions.js +56 -0
  54. package/dist/http/request.d.ts +44 -0
  55. package/dist/http/request.js +83 -0
  56. package/dist/index.d.ts +21 -0
  57. package/dist/index.js +19 -0
  58. package/dist/indicators/builtin-indicator.d.ts +17 -0
  59. package/dist/indicators/builtin-indicator.js +75 -0
  60. package/dist/indicators/index.d.ts +8 -0
  61. package/dist/indicators/index.js +2 -0
  62. package/dist/indicators/pine-indicator.d.ts +63 -0
  63. package/dist/indicators/pine-indicator.js +101 -0
  64. package/dist/protocol/compression.d.ts +12 -0
  65. package/dist/protocol/compression.js +83 -0
  66. package/dist/protocol/framing.d.ts +59 -0
  67. package/dist/protocol/framing.js +68 -0
  68. package/dist/protocol/ids.d.ts +2 -0
  69. package/dist/protocol/ids.js +10 -0
  70. package/dist/protocol/index.d.ts +4 -0
  71. package/dist/protocol/index.js +3 -0
  72. package/dist/quote/fields.d.ts +35 -0
  73. package/dist/quote/fields.js +21 -0
  74. package/dist/quote/index.d.ts +4 -0
  75. package/dist/quote/index.js +2 -0
  76. package/dist/quote/quote-session.d.ts +73 -0
  77. package/dist/quote/quote-session.js +205 -0
  78. package/docs/README.es.md +58 -0
  79. package/docs/README.fr.md +58 -0
  80. package/docs/README.pt.md +58 -0
  81. package/docs/data-api.md +229 -0
  82. package/docs/low-level-api.md +213 -0
  83. package/docs/migration-v4.md +128 -0
  84. package/docs/v4-coverage.md +192 -0
  85. package/docs/v4-reliability.md +33 -0
  86. package/package.json +55 -20
  87. package/.env.sample +0 -2
  88. package/.eslintrc.js +0 -28
  89. package/.gitattributes +0 -2
  90. package/docs/DOCS.md +0 -3
  91. package/examples/AllPrivateIndicators.js +0 -44
  92. package/examples/BuiltInIndicator.js +0 -51
  93. package/examples/CustomChartType.js +0 -123
  94. package/examples/CustomTimeframe.js +0 -31
  95. package/examples/Errors.js +0 -155
  96. package/examples/FakeReplayMode.js +0 -40
  97. package/examples/FromToData.js +0 -35
  98. package/examples/GetDrawings.js +0 -27
  99. package/examples/GraphicIndicator.js +0 -42
  100. package/examples/MultipleSyncFetch.js +0 -44
  101. package/examples/PinePermManage.js +0 -67
  102. package/examples/ReplayMode.js +0 -103
  103. package/examples/Search.js +0 -14
  104. package/examples/SimpleChart.js +0 -63
  105. package/examples/UserLogin.js +0 -16
  106. package/main.js +0 -11
  107. package/src/chart/graphicParser.js +0 -308
  108. package/src/chart/session.js +0 -553
  109. package/src/chart/study.js +0 -435
  110. package/src/classes/BuiltInIndicator.js +0 -137
  111. package/src/classes/PineIndicator.js +0 -132
  112. package/src/classes/PinePermManager.js +0 -159
  113. package/src/client.js +0 -294
  114. package/src/miscRequests.js +0 -607
  115. package/src/protocol.js +0 -60
  116. package/src/quote/market.js +0 -132
  117. package/src/quote/session.js +0 -125
  118. package/src/types.js +0 -36
  119. package/src/utils.js +0 -20
  120. package/vite.config.js +0 -7
@@ -1,607 +0,0 @@
1
- const os = require('os');
2
- const axios = require('axios');
3
-
4
- const PineIndicator = require('./classes/PineIndicator');
5
- const { genAuthCookies } = require('./utils');
6
-
7
- const validateStatus = (status) => status < 500;
8
-
9
- const indicators = ['Recommend.Other', 'Recommend.All', 'Recommend.MA'];
10
- const builtInIndicList = [];
11
-
12
- async function fetchScanData(tickers = [], columns = []) {
13
- const { data } = await axios.post(
14
- 'https://scanner.tradingview.com/global/scan',
15
- {
16
- symbols: { tickers },
17
- columns,
18
- },
19
- { validateStatus },
20
- );
21
-
22
- return data;
23
- }
24
-
25
- /** @typedef {number} advice */
26
-
27
- /**
28
- * @typedef {{
29
- * Other: advice,
30
- * All: advice,
31
- * MA: advice
32
- * }} Period
33
- */
34
-
35
- /**
36
- * @typedef {{
37
- * '1': Period,
38
- * '5': Period,
39
- * '15': Period,
40
- * '60': Period,
41
- * '240': Period,
42
- * '1D': Period,
43
- * '1W': Period,
44
- * '1M': Period
45
- * }} Periods
46
- */
47
-
48
- module.exports = {
49
- /**
50
- * Get technical analysis
51
- * @function getTA
52
- * @param {string} id Full market id (Example: COINBASE:BTCEUR)
53
- * @returns {Promise<Periods>} results
54
- */
55
- async getTA(id) {
56
- const advice = {};
57
-
58
- const cols = ['1', '5', '15', '60', '240', '1D', '1W', '1M']
59
- .map((t) => indicators.map((i) => (t !== '1D' ? `${i}|${t}` : i)))
60
- .flat();
61
-
62
- const rs = await fetchScanData([id], cols);
63
- if (!rs.data || !rs.data[0]) return false;
64
-
65
- rs.data[0].d.forEach((val, i) => {
66
- const [name, period] = cols[i].split('|');
67
- const pName = period || '1D';
68
- if (!advice[pName]) advice[pName] = {};
69
- advice[pName][name.split('.').pop()] = Math.round(val * 1000) / 500;
70
- });
71
-
72
- return advice;
73
- },
74
-
75
- /**
76
- * @typedef {Object} SearchMarketResult
77
- * @prop {string} id Market full symbol
78
- * @prop {string} exchange Market exchange name
79
- * @prop {string} fullExchange Market exchange full name
80
- * @prop {string} symbol Market symbol
81
- * @prop {string} description Market name
82
- * @prop {string} type Market type
83
- * @prop {() => Promise<Periods>} getTA Get market technical analysis
84
- */
85
-
86
- /**
87
- * Find a symbol (deprecated)
88
- * @function searchMarket
89
- * @param {string} search Keywords
90
- * @param {'stock'
91
- * | 'futures' | 'forex' | 'cfd'
92
- * | 'crypto' | 'index' | 'economic'
93
- * } [filter] Caterogy filter
94
- * @returns {Promise<SearchMarketResult[]>} Search results
95
- * @deprecated Use searchMarketV3 instead
96
- */
97
- async searchMarket(search, filter = '') {
98
- const { data } = await axios.get(
99
- 'https://symbol-search.tradingview.com/symbol_search',
100
- {
101
- params: {
102
- text: search.replace(/ /g, '%20'),
103
- type: filter,
104
- },
105
- headers: {
106
- origin: 'https://www.tradingview.com',
107
- },
108
- validateStatus,
109
- },
110
- );
111
-
112
- return data.map((s) => {
113
- const exchange = s.exchange.split(' ')[0];
114
- const id = `${exchange}:${s.symbol}`;
115
-
116
- return {
117
- id,
118
- exchange,
119
- fullExchange: s.exchange,
120
- symbol: s.symbol,
121
- description: s.description,
122
- type: s.type,
123
- getTA: () => this.getTA(id),
124
- };
125
- });
126
- },
127
-
128
- /**
129
- * Find a symbol
130
- * @function searchMarketV3
131
- * @param {string} search Keywords
132
- * @param {'stock'
133
- * | 'futures' | 'forex' | 'cfd'
134
- * | 'crypto' | 'index' | 'economic'
135
- * } [filter] Caterogy filter
136
- * @returns {Promise<SearchMarketResult[]>} Search results
137
- */
138
- async searchMarketV3(search, filter = '') {
139
- const splittedSearch = search.toUpperCase().replace(/ /g, '+').split(':');
140
-
141
- const request = await axios.get(
142
- 'https://symbol-search.tradingview.com/symbol_search/v3',
143
- {
144
- params: {
145
- exchange: (splittedSearch.length === 2
146
- ? splittedSearch[0]
147
- : undefined
148
- ),
149
- text: splittedSearch.pop(),
150
- search_type: filter,
151
- },
152
- headers: {
153
- origin: 'https://www.tradingview.com',
154
- },
155
- validateStatus,
156
- },
157
- );
158
-
159
- const { data } = request;
160
-
161
- return data.symbols.map((s) => {
162
- const exchange = s.exchange.split(' ')[0];
163
- const id = `${exchange.toUpperCase()}:${s.symbol}`;
164
-
165
- return {
166
- id,
167
- exchange,
168
- fullExchange: s.exchange,
169
- symbol: s.symbol,
170
- description: s.description,
171
- type: s.type,
172
- getTA: () => this.getTA(id),
173
- };
174
- });
175
- },
176
-
177
- /**
178
- * @typedef {Object} SearchIndicatorResult
179
- * @prop {string} id Script ID
180
- * @prop {string} version Script version
181
- * @prop {string} name Script complete name
182
- * @prop {{ id: number, username: string }} author Author user ID
183
- * @prop {string} image Image ID https://tradingview.com/i/${image}
184
- * @prop {string | ''} source Script source (if available)
185
- * @prop {'study' | 'strategy'} type Script type (study / strategy)
186
- * @prop {'open_source' | 'closed_source' | 'invite_only'
187
- * | 'private' | 'other'} access Script access type
188
- * @prop {() => Promise<PineIndicator>} get Get the full indicator informations
189
- */
190
-
191
- /**
192
- * Find an indicator
193
- * @function searchIndicator
194
- * @param {string} search Keywords
195
- * @returns {Promise<SearchIndicatorResult[]>} Search results
196
- */
197
- async searchIndicator(search = '') {
198
- if (!builtInIndicList.length) {
199
- await Promise.all(['standard', 'candlestick', 'fundamental'].map(async (type) => {
200
- const { data } = await axios.get(
201
- 'https://pine-facade.tradingview.com/pine-facade/list',
202
- {
203
- params: {
204
- filter: type,
205
- },
206
- validateStatus,
207
- },
208
- );
209
- builtInIndicList.push(...data);
210
- }));
211
- }
212
-
213
- const { data } = await axios.get(
214
- 'https://www.tradingview.com/pubscripts-suggest-json',
215
- {
216
- params: {
217
- search: search.replace(/ /g, '%20'),
218
- },
219
- validateStatus,
220
- },
221
- );
222
-
223
- function norm(str = '') {
224
- return str.toUpperCase().replace(/[^A-Z]/g, '');
225
- }
226
-
227
- return [
228
- ...builtInIndicList.filter((i) => (
229
- norm(i.scriptName).includes(norm(search))
230
- || norm(i.extra.shortDescription).includes(norm(search))
231
- )).map((ind) => ({
232
- id: ind.scriptIdPart,
233
- version: ind.version,
234
- name: ind.scriptName,
235
- author: {
236
- id: ind.userId,
237
- username: '@TRADINGVIEW@',
238
- },
239
- image: '',
240
- access: 'closed_source',
241
- source: '',
242
- type: (ind.extra && ind.extra.kind) ? ind.extra.kind : 'study',
243
- get() {
244
- return module.exports.getIndicator(ind.scriptIdPart, ind.version);
245
- },
246
- })),
247
-
248
- ...data.results.map((ind) => ({
249
- id: ind.scriptIdPart,
250
- version: ind.version,
251
- name: ind.scriptName,
252
- author: {
253
- id: ind.author.id,
254
- username: ind.author.username,
255
- },
256
- image: ind.imageUrl,
257
- access: ['open_source', 'closed_source', 'invite_only'][ind.access - 1] || 'other',
258
- source: ind.scriptSource,
259
- type: (ind.extra && ind.extra.kind) ? ind.extra.kind : 'study',
260
- get() {
261
- return module.exports.getIndicator(ind.scriptIdPart, ind.version);
262
- },
263
- })),
264
- ];
265
- },
266
-
267
- /**
268
- * Get an indicator
269
- * @function getIndicator
270
- * @param {string} id Indicator ID (Like: PUB;XXXXXXXXXXXXXXXXXXXXX)
271
- * @param {'last' | string} [version] Wanted version of the indicator
272
- * @param {string} [session] User 'sessionid' cookie
273
- * @param {string} [signature] User 'sessionid_sign' cookie
274
- * @returns {Promise<PineIndicator>} Indicator
275
- */
276
- async getIndicator(id, version = 'last', session = '', signature = '') {
277
- const indicID = id.replace(/ |%/g, '%25');
278
-
279
- const { data } = await axios.get(
280
- `https://pine-facade.tradingview.com/pine-facade/translate/${indicID}/${version}`,
281
- {
282
- headers: {
283
- cookie: genAuthCookies(session, signature),
284
- },
285
- validateStatus,
286
- },
287
- );
288
-
289
- if (!data.success || !data.result.metaInfo || !data.result.metaInfo.inputs) {
290
- throw new Error(`Inexistent or unsupported indicator: "${data.reason}"`);
291
- }
292
-
293
- const inputs = {};
294
-
295
- data.result.metaInfo.inputs.forEach((input) => {
296
- if (['text', 'pineId', 'pineVersion'].includes(input.id)) return;
297
-
298
- const inlineName = input.name.replace(/ /g, '_').replace(/[^a-zA-Z0-9_]/g, '');
299
-
300
- inputs[input.id] = {
301
- name: input.name,
302
- inline: input.inline || inlineName,
303
- internalID: input.internalID || inlineName,
304
- tooltip: input.tooltip,
305
-
306
- type: input.type,
307
- value: input.defval,
308
- isHidden: !!input.isHidden,
309
- isFake: !!input.isFake,
310
- };
311
-
312
- if (input.options) inputs[input.id].options = input.options;
313
- });
314
-
315
- const plots = {};
316
-
317
- Object.keys(data.result.metaInfo.styles).forEach((plotId) => {
318
- const plotTitle = data
319
- .result
320
- .metaInfo
321
- .styles[plotId]
322
- .title
323
- .replace(/ /g, '_')
324
- .replace(/[^a-zA-Z0-9_]/g, '');
325
-
326
- const titles = Object.values(plots);
327
-
328
- if (titles.includes(plotTitle)) {
329
- let i = 2;
330
- while (titles.includes(`${plotTitle}_${i}`)) i += 1;
331
- plots[plotId] = `${plotTitle}_${i}`;
332
- } else plots[plotId] = plotTitle;
333
- });
334
-
335
- data.result.metaInfo.plots.forEach((plot) => {
336
- if (!plot.target) return;
337
- plots[plot.id] = `${plots[plot.target] ?? plot.target}_${plot.type}`;
338
- });
339
-
340
- return new PineIndicator({
341
- pineId: data.result.metaInfo.scriptIdPart || indicID,
342
- pineVersion: data.result.metaInfo.pine.version || version,
343
- description: data.result.metaInfo.description,
344
- shortDescription: data.result.metaInfo.shortDescription,
345
- inputs,
346
- plots,
347
- script: data.result.ilTemplate,
348
- });
349
- },
350
-
351
- /**
352
- * @typedef {Object} User Instance of User
353
- * @prop {number} id User ID
354
- * @prop {string} username User username
355
- * @prop {string} firstName User first name
356
- * @prop {string} lastName User last name
357
- * @prop {number} reputation User reputation
358
- * @prop {number} following Number of following accounts
359
- * @prop {number} followers Number of followers
360
- * @prop {Object} notifications User's notifications
361
- * @prop {number} notifications.user User notifications
362
- * @prop {number} notifications.following Notification from following accounts
363
- * @prop {string} session User session
364
- * @prop {string} sessionHash User session hash
365
- * @prop {string} signature User session signature
366
- * @prop {string} privateChannel User private channel
367
- * @prop {string} authToken User auth token
368
- * @prop {Date} joinDate Account creation date
369
- */
370
-
371
- /**
372
- * Get user and sessionid from username/email and password
373
- * @function loginUser
374
- * @param {string} username User username/email
375
- * @param {string} password User password
376
- * @param {boolean} [remember] Remember the session (default: false)
377
- * @param {string} [UA] Custom UserAgent
378
- * @returns {Promise<User>} Token
379
- */
380
- async loginUser(username, password, remember = true, UA = 'TWAPI/3.0') {
381
- const { data, headers } = await axios.post(
382
- 'https://www.tradingview.com/accounts/signin/',
383
- `username=${username}&password=${password}${remember ? '&remember=on' : ''}`,
384
- {
385
- headers: {
386
- referer: 'https://www.tradingview.com',
387
- 'Content-Type': 'application/x-www-form-urlencoded',
388
- 'User-agent': `${UA} (${os.version()}; ${os.platform()}; ${os.arch()})`,
389
- },
390
- validateStatus,
391
- },
392
- );
393
-
394
- const cookies = headers['set-cookie'];
395
-
396
- if (data.error) throw new Error(data.error);
397
-
398
- const sessionCookie = cookies.find((c) => c.includes('sessionid='));
399
- const session = (sessionCookie.match(/sessionid=(.*?);/) ?? [])[1];
400
-
401
- const signCookie = cookies.find((c) => c.includes('sessionid_sign='));
402
- const signature = (signCookie.match(/sessionid_sign=(.*?);/) ?? [])[1];
403
-
404
- return {
405
- id: data.user.id,
406
- username: data.user.username,
407
- firstName: data.user.first_name,
408
- lastName: data.user.last_name,
409
- reputation: data.user.reputation,
410
- following: data.user.following,
411
- followers: data.user.followers,
412
- notifications: data.user.notification_count,
413
- session,
414
- signature,
415
- sessionHash: data.user.session_hash,
416
- privateChannel: data.user.private_channel,
417
- authToken: data.user.auth_token,
418
- joinDate: new Date(data.user.date_joined),
419
- };
420
- },
421
-
422
- /**
423
- * Get user from 'sessionid' cookie
424
- * @function getUser
425
- * @param {string} session User 'sessionid' cookie
426
- * @param {string} [signature] User 'sessionid_sign' cookie
427
- * @param {string} [location] Auth page location (For france: https://fr.tradingview.com/)
428
- * @returns {Promise<User>} Token
429
- */
430
- async getUser(session, signature = '', location = 'https://www.tradingview.com/') {
431
- const { data, headers } = await axios.get(location, {
432
- headers: {
433
- cookie: genAuthCookies(session, signature),
434
- },
435
- maxRedirects: 0,
436
- validateStatus,
437
- });
438
-
439
- if (data.includes('auth_token')) {
440
- return {
441
- id: /"id":([0-9]{1,10}),/.exec(data)?.[1],
442
- username: /"username":"(.*?)"/.exec(data)?.[1],
443
- firstName: /"first_name":"(.*?)"/.exec(data)?.[1],
444
- lastName: /"last_name":"(.*?)"/.exec(data)?.[1],
445
- reputation: parseFloat(/"reputation":(.*?),/.exec(data)?.[1] || 0),
446
- following: parseFloat(/,"following":([0-9]*?),/.exec(data)?.[1] || 0),
447
- followers: parseFloat(/,"followers":([0-9]*?),/.exec(data)?.[1] || 0),
448
- notifications: {
449
- following: parseFloat(/"notification_count":\{"following":([0-9]*),/.exec(data)?.[1] ?? 0),
450
- user: parseFloat(/"notification_count":\{"following":[0-9]*,"user":([0-9]*)/.exec(data)?.[1] ?? 0),
451
- },
452
- session,
453
- signature,
454
- sessionHash: /"session_hash":"(.*?)"/.exec(data)?.[1],
455
- privateChannel: /"private_channel":"(.*?)"/.exec(data)?.[1],
456
- authToken: /"auth_token":"(.*?)"/.exec(data)?.[1],
457
- joinDate: new Date(/"date_joined":"(.*?)"/.exec(data)?.[1] || 0),
458
- };
459
- }
460
-
461
- if (headers.location !== location) {
462
- return this.getUser(session, signature, headers.location);
463
- }
464
-
465
- throw new Error('Wrong or expired sessionid/signature');
466
- },
467
-
468
- /**
469
- * Get user's private indicators from a 'sessionid' cookie
470
- * @function getPrivateIndicators
471
- * @param {string} session User 'sessionid' cookie
472
- * @param {string} [signature] User 'sessionid_sign' cookie
473
- * @returns {Promise<SearchIndicatorResult[]>} Search results
474
- */
475
- async getPrivateIndicators(session, signature = '') {
476
- const { data } = await axios.get(
477
- 'https://pine-facade.tradingview.com/pine-facade/list',
478
- {
479
- headers: {
480
- cookie: genAuthCookies(session, signature),
481
- },
482
- params: {
483
- filter: 'saved',
484
- },
485
- validateStatus,
486
- },
487
- );
488
-
489
- return data.map((ind) => ({
490
- id: ind.scriptIdPart,
491
- version: ind.version,
492
- name: ind.scriptName,
493
- author: {
494
- id: -1,
495
- username: '@ME@',
496
- },
497
- image: ind.imageUrl,
498
- access: 'private',
499
- source: ind.scriptSource,
500
- type: (ind.extra && ind.extra.kind) ? ind.extra.kind : 'study',
501
- get() {
502
- return module.exports.getIndicator(
503
- ind.scriptIdPart,
504
- ind.version,
505
- session,
506
- signature,
507
- );
508
- },
509
- }));
510
- },
511
-
512
- /**
513
- * User credentials
514
- * @typedef {Object} UserCredentials
515
- * @prop {number} id User ID
516
- * @prop {string} session User session ('sessionid' cookie)
517
- * @prop {string} [signature] User session signature ('sessionid_sign' cookie)
518
- */
519
-
520
- /**
521
- * Get a chart token from a layout ID and the user credentials if the layout is not public
522
- * @function getChartToken
523
- * @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
524
- * @param {UserCredentials} [credentials] User credentials (id + session + [signature])
525
- * @returns {Promise<string>} Token
526
- */
527
- async getChartToken(layout, credentials = {}) {
528
- const { id, session, signature } = (
529
- credentials.id && credentials.session
530
- ? credentials
531
- : { id: -1, session: null, signature: null }
532
- );
533
-
534
- const { data } = await axios.get(
535
- 'https://www.tradingview.com/chart-token',
536
- {
537
- headers: {
538
- cookie: genAuthCookies(session, signature),
539
- },
540
- params: {
541
- image_url: layout,
542
- user_id: id,
543
- },
544
- validateStatus,
545
- },
546
- );
547
-
548
- if (!data.token) throw new Error('Wrong layout or credentials');
549
-
550
- return data.token;
551
- },
552
-
553
- /**
554
- * @typedef {Object} DrawingPoint Drawing poitn
555
- * @prop {number} time_t Point X time position
556
- * @prop {number} price Point Y price position
557
- * @prop {number} offset Point offset
558
- */
559
-
560
- /**
561
- * @typedef {Object} Drawing
562
- * @prop {string} id Drawing ID (Like: 'XXXXXX')
563
- * @prop {string} symbol Layout market symbol (Like: 'BINANCE:BUCEUR')
564
- * @prop {string} ownerSource Owner user ID (Like: 'XXXXXX')
565
- * @prop {string} serverUpdateTime Drawing last update timestamp
566
- * @prop {string} currencyId Currency ID (Like: 'EUR')
567
- * @prop {any} unitId Unit ID
568
- * @prop {string} type Drawing type
569
- * @prop {DrawingPoint[]} points List of drawing points
570
- * @prop {number} zorder Drawing Z order
571
- * @prop {string} linkKey Drawing link key
572
- * @prop {Object} state Drawing state
573
- */
574
-
575
- /**
576
- * Get a chart token from a layout ID and the user credentials if the layout is not public
577
- * @function getDrawings
578
- * @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
579
- * @param {string | ''} [symbol] Market filter (Like: 'BINANCE:BTCEUR')
580
- * @param {UserCredentials} [credentials] User credentials (id + session + [signature])
581
- * @param {number} [chartID] Chart ID
582
- * @returns {Promise<Drawing[]>} Drawings
583
- */
584
- async getDrawings(layout, symbol = '', credentials = {}, chartID = '_shared') {
585
- const chartToken = await module.exports.getChartToken(layout, credentials);
586
-
587
- const { data } = await axios.get(
588
- `https://charts-storage.tradingview.com/charts-storage/get/layout/${
589
- layout
590
- }/sources`,
591
- {
592
- params: {
593
- chart_id: chartID,
594
- jwt: chartToken,
595
- symbol,
596
- },
597
- validateStatus,
598
- },
599
- );
600
-
601
- if (!data.payload) throw new Error('Wrong layout, user credentials, or chart id.');
602
-
603
- return Object.values(data.payload.sources || {}).map((drawing) => ({
604
- ...drawing, ...drawing.state,
605
- }));
606
- },
607
- };
package/src/protocol.js DELETED
@@ -1,60 +0,0 @@
1
- const JSZip = require('jszip');
2
-
3
- /**
4
- * @typedef {Object} TWPacket
5
- * @prop {string} [m] Packet type
6
- * @prop {[session: string, {}]} [p] Packet data
7
- */
8
-
9
- const cleanerRgx = /~h~/g;
10
- const splitterRgx = /~m~[0-9]{1,}~m~/g;
11
-
12
- module.exports = {
13
- /**
14
- * Parse websocket packet
15
- * @function parseWSPacket
16
- * @param {string} str Websocket raw data
17
- * @returns {TWPacket[]} TradingView packets
18
- */
19
- parseWSPacket(str) {
20
- return str.replace(cleanerRgx, '').split(splitterRgx)
21
- .map((p) => {
22
- if (!p) return false;
23
- try {
24
- return JSON.parse(p);
25
- } catch (error) {
26
- console.warn('Cant parse', p);
27
- return false;
28
- }
29
- })
30
- .filter((p) => p);
31
- },
32
-
33
- /**
34
- * Format websocket packet
35
- * @function formatWSPacket
36
- * @param {TWPacket} packet TradingView packet
37
- * @returns {string} Websocket raw data
38
- */
39
- formatWSPacket(packet) {
40
- const msg = typeof packet === 'object'
41
- ? JSON.stringify(packet)
42
- : packet;
43
- return `~m~${msg.length}~m~${msg}`;
44
- },
45
-
46
- /**
47
- * Parse compressed data
48
- * @function parseCompressed
49
- * @param {string} data Compressed data
50
- * @returns {Promise<{}>} Parsed data
51
- */
52
- async parseCompressed(data) {
53
- const zip = new JSZip();
54
- return JSON.parse(
55
- await (
56
- await zip.loadAsync(data, { base64: true })
57
- ).file('').async('text'),
58
- );
59
- },
60
- };