@mathieuc/tradingview 3.5.2 → 4.0.0-beta.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.
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 +113 -0
  9. package/dist/chart/strategy.js +78 -0
  10. package/dist/chart/study.d.ts +60 -0
  11. package/dist/chart/study.js +179 -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 +30 -0
  27. package/dist/data/index.js +16 -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 +285 -0
  82. package/docs/low-level-api.md +213 -0
  83. package/docs/migration-v4.md +128 -0
  84. package/docs/release-4.0.0-beta.1.md +39 -0
  85. package/docs/v4-coverage.md +213 -0
  86. package/package.json +53 -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 -298
  114. package/src/miscRequests.js +0 -609
  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,609 +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
- * @param {number} offset Pagination offset
137
- * @returns {Promise<SearchMarketResult[]>} Search results
138
- */
139
- async searchMarketV3(search, filter = '', offset = 0) {
140
- const splittedSearch = search.toUpperCase().replace(/ /g, '+').split(':');
141
-
142
- const request = await axios.get(
143
- 'https://symbol-search.tradingview.com/symbol_search/v3',
144
- {
145
- params: {
146
- exchange: (splittedSearch.length === 2
147
- ? splittedSearch[0]
148
- : undefined
149
- ),
150
- text: splittedSearch.pop(),
151
- search_type: filter,
152
- start: offset,
153
- },
154
- headers: {
155
- origin: 'https://www.tradingview.com',
156
- },
157
- validateStatus,
158
- },
159
- );
160
-
161
- const { data } = request;
162
-
163
- return data.symbols.map((s) => {
164
- const exchange = s.exchange.split(' ')[0];
165
- const id = s.prefix ? `${s.prefix}:${s.symbol}` : `${exchange.toUpperCase()}:${s.symbol}`;
166
-
167
- return {
168
- id,
169
- exchange,
170
- fullExchange: s.exchange,
171
- symbol: s.symbol,
172
- description: s.description,
173
- type: s.type,
174
- getTA: () => this.getTA(id),
175
- };
176
- });
177
- },
178
-
179
- /**
180
- * @typedef {Object} SearchIndicatorResult
181
- * @prop {string} id Script ID
182
- * @prop {string} version Script version
183
- * @prop {string} name Script complete name
184
- * @prop {{ id: number, username: string }} author Author user ID
185
- * @prop {string} image Image ID https://tradingview.com/i/${image}
186
- * @prop {string | ''} source Script source (if available)
187
- * @prop {'study' | 'strategy'} type Script type (study / strategy)
188
- * @prop {'open_source' | 'closed_source' | 'invite_only'
189
- * | 'private' | 'other'} access Script access type
190
- * @prop {() => Promise<PineIndicator>} get Get the full indicator informations
191
- */
192
-
193
- /**
194
- * Find an indicator
195
- * @function searchIndicator
196
- * @param {string} search Keywords
197
- * @returns {Promise<SearchIndicatorResult[]>} Search results
198
- */
199
- async searchIndicator(search = '') {
200
- if (!builtInIndicList.length) {
201
- await Promise.all(['standard', 'candlestick', 'fundamental'].map(async (type) => {
202
- const { data } = await axios.get(
203
- 'https://pine-facade.tradingview.com/pine-facade/list',
204
- {
205
- params: {
206
- filter: type,
207
- },
208
- validateStatus,
209
- },
210
- );
211
- builtInIndicList.push(...data);
212
- }));
213
- }
214
-
215
- const { data } = await axios.get(
216
- 'https://www.tradingview.com/pubscripts-suggest-json',
217
- {
218
- params: {
219
- search: search.replace(/ /g, '%20'),
220
- },
221
- validateStatus,
222
- },
223
- );
224
-
225
- function norm(str = '') {
226
- return str.toUpperCase().replace(/[^A-Z]/g, '');
227
- }
228
-
229
- return [
230
- ...builtInIndicList.filter((i) => (
231
- norm(i.scriptName).includes(norm(search))
232
- || norm(i.extra.shortDescription).includes(norm(search))
233
- )).map((ind) => ({
234
- id: ind.scriptIdPart,
235
- version: ind.version,
236
- name: ind.scriptName,
237
- author: {
238
- id: ind.userId,
239
- username: '@TRADINGVIEW@',
240
- },
241
- image: '',
242
- access: 'closed_source',
243
- source: '',
244
- type: (ind.extra && ind.extra.kind) ? ind.extra.kind : 'study',
245
- get() {
246
- return module.exports.getIndicator(ind.scriptIdPart, ind.version);
247
- },
248
- })),
249
-
250
- ...data.results.map((ind) => ({
251
- id: ind.scriptIdPart,
252
- version: ind.version,
253
- name: ind.scriptName,
254
- author: {
255
- id: ind.author.id,
256
- username: ind.author.username,
257
- },
258
- image: ind.imageUrl,
259
- access: ['open_source', 'closed_source', 'invite_only'][ind.access - 1] || 'other',
260
- source: ind.scriptSource,
261
- type: (ind.extra && ind.extra.kind) ? ind.extra.kind : 'study',
262
- get() {
263
- return module.exports.getIndicator(ind.scriptIdPart, ind.version);
264
- },
265
- })),
266
- ];
267
- },
268
-
269
- /**
270
- * Get an indicator
271
- * @function getIndicator
272
- * @param {string} id Indicator ID (Like: PUB;XXXXXXXXXXXXXXXXXXXXX)
273
- * @param {'last' | string} [version] Wanted version of the indicator
274
- * @param {string} [session] User 'sessionid' cookie
275
- * @param {string} [signature] User 'sessionid_sign' cookie
276
- * @returns {Promise<PineIndicator>} Indicator
277
- */
278
- async getIndicator(id, version = 'last', session = '', signature = '') {
279
- const indicID = id.replace(/ |%/g, '%25');
280
-
281
- const { data } = await axios.get(
282
- `https://pine-facade.tradingview.com/pine-facade/translate/${indicID}/${version}`,
283
- {
284
- headers: {
285
- cookie: genAuthCookies(session, signature),
286
- },
287
- validateStatus,
288
- },
289
- );
290
-
291
- if (!data.success || !data.result.metaInfo || !data.result.metaInfo.inputs) {
292
- throw new Error(`Inexistent or unsupported indicator: "${data.reason}"`);
293
- }
294
-
295
- const inputs = {};
296
-
297
- data.result.metaInfo.inputs.forEach((input) => {
298
- if (['text', 'pineId', 'pineVersion'].includes(input.id)) return;
299
-
300
- const inlineName = input.name.replace(/ /g, '_').replace(/[^a-zA-Z0-9_]/g, '');
301
-
302
- inputs[input.id] = {
303
- name: input.name,
304
- inline: input.inline || inlineName,
305
- internalID: input.internalID || inlineName,
306
- tooltip: input.tooltip,
307
-
308
- type: input.type,
309
- value: input.defval,
310
- isHidden: !!input.isHidden,
311
- isFake: !!input.isFake,
312
- };
313
-
314
- if (input.options) inputs[input.id].options = input.options;
315
- });
316
-
317
- const plots = {};
318
-
319
- Object.keys(data.result.metaInfo.styles).forEach((plotId) => {
320
- const plotTitle = data
321
- .result
322
- .metaInfo
323
- .styles[plotId]
324
- .title
325
- .replace(/ /g, '_')
326
- .replace(/[^a-zA-Z0-9_]/g, '');
327
-
328
- const titles = Object.values(plots);
329
-
330
- if (titles.includes(plotTitle)) {
331
- let i = 2;
332
- while (titles.includes(`${plotTitle}_${i}`)) i += 1;
333
- plots[plotId] = `${plotTitle}_${i}`;
334
- } else plots[plotId] = plotTitle;
335
- });
336
-
337
- data.result.metaInfo.plots.forEach((plot) => {
338
- if (!plot.target) return;
339
- plots[plot.id] = `${plots[plot.target] ?? plot.target}_${plot.type}`;
340
- });
341
-
342
- return new PineIndicator({
343
- pineId: data.result.metaInfo.scriptIdPart || indicID,
344
- pineVersion: data.result.metaInfo.pine.version || version,
345
- description: data.result.metaInfo.description,
346
- shortDescription: data.result.metaInfo.shortDescription,
347
- inputs,
348
- plots,
349
- script: data.result.ilTemplate,
350
- });
351
- },
352
-
353
- /**
354
- * @typedef {Object} User Instance of User
355
- * @prop {number} id User ID
356
- * @prop {string} username User username
357
- * @prop {string} firstName User first name
358
- * @prop {string} lastName User last name
359
- * @prop {number} reputation User reputation
360
- * @prop {number} following Number of following accounts
361
- * @prop {number} followers Number of followers
362
- * @prop {Object} notifications User's notifications
363
- * @prop {number} notifications.user User notifications
364
- * @prop {number} notifications.following Notification from following accounts
365
- * @prop {string} session User session
366
- * @prop {string} sessionHash User session hash
367
- * @prop {string} signature User session signature
368
- * @prop {string} privateChannel User private channel
369
- * @prop {string} authToken User auth token
370
- * @prop {Date} joinDate Account creation date
371
- */
372
-
373
- /**
374
- * Get user and sessionid from username/email and password
375
- * @function loginUser
376
- * @param {string} username User username/email
377
- * @param {string} password User password
378
- * @param {boolean} [remember] Remember the session (default: false)
379
- * @param {string} [UA] Custom UserAgent
380
- * @returns {Promise<User>} Token
381
- */
382
- async loginUser(username, password, remember = true, UA = 'TWAPI/3.0') {
383
- const { data, headers } = await axios.post(
384
- 'https://www.tradingview.com/accounts/signin/',
385
- `username=${username}&password=${password}${remember ? '&remember=on' : ''}`,
386
- {
387
- headers: {
388
- referer: 'https://www.tradingview.com',
389
- 'Content-Type': 'application/x-www-form-urlencoded',
390
- 'User-agent': `${UA} (${os.version()}; ${os.platform()}; ${os.arch()})`,
391
- },
392
- validateStatus,
393
- },
394
- );
395
-
396
- const cookies = headers['set-cookie'];
397
-
398
- if (data.error) throw new Error(data.error);
399
-
400
- const sessionCookie = cookies.find((c) => c.includes('sessionid='));
401
- const session = (sessionCookie.match(/sessionid=(.*?);/) ?? [])[1];
402
-
403
- const signCookie = cookies.find((c) => c.includes('sessionid_sign='));
404
- const signature = (signCookie.match(/sessionid_sign=(.*?);/) ?? [])[1];
405
-
406
- return {
407
- id: data.user.id,
408
- username: data.user.username,
409
- firstName: data.user.first_name,
410
- lastName: data.user.last_name,
411
- reputation: data.user.reputation,
412
- following: data.user.following,
413
- followers: data.user.followers,
414
- notifications: data.user.notification_count,
415
- session,
416
- signature,
417
- sessionHash: data.user.session_hash,
418
- privateChannel: data.user.private_channel,
419
- authToken: data.user.auth_token,
420
- joinDate: new Date(data.user.date_joined),
421
- };
422
- },
423
-
424
- /**
425
- * Get user from 'sessionid' cookie
426
- * @function getUser
427
- * @param {string} session User 'sessionid' cookie
428
- * @param {string} [signature] User 'sessionid_sign' cookie
429
- * @param {string} [location] Auth page location (For france: https://fr.tradingview.com/)
430
- * @returns {Promise<User>} Token
431
- */
432
- async getUser(session, signature = '', location = 'https://www.tradingview.com/') {
433
- const { data, headers } = await axios.get(location, {
434
- headers: {
435
- cookie: genAuthCookies(session, signature),
436
- },
437
- maxRedirects: 0,
438
- validateStatus,
439
- });
440
-
441
- if (data.includes('auth_token')) {
442
- return {
443
- id: /"id":([0-9]{1,10}),/.exec(data)?.[1],
444
- username: /"username":"(.*?)"/.exec(data)?.[1],
445
- firstName: /"first_name":"(.*?)"/.exec(data)?.[1],
446
- lastName: /"last_name":"(.*?)"/.exec(data)?.[1],
447
- reputation: parseFloat(/"reputation":(.*?),/.exec(data)?.[1] || 0),
448
- following: parseFloat(/,"following":([0-9]*?),/.exec(data)?.[1] || 0),
449
- followers: parseFloat(/,"followers":([0-9]*?),/.exec(data)?.[1] || 0),
450
- notifications: {
451
- following: parseFloat(/"notification_count":\{"following":([0-9]*),/.exec(data)?.[1] ?? 0),
452
- user: parseFloat(/"notification_count":\{"following":[0-9]*,"user":([0-9]*)/.exec(data)?.[1] ?? 0),
453
- },
454
- session,
455
- signature,
456
- sessionHash: /"session_hash":"(.*?)"/.exec(data)?.[1],
457
- privateChannel: /"private_channel":"(.*?)"/.exec(data)?.[1],
458
- authToken: /"auth_token":"(.*?)"/.exec(data)?.[1],
459
- joinDate: new Date(/"date_joined":"(.*?)"/.exec(data)?.[1] || 0),
460
- };
461
- }
462
-
463
- if (headers.location !== location) {
464
- return this.getUser(session, signature, headers.location);
465
- }
466
-
467
- throw new Error('Wrong or expired sessionid/signature');
468
- },
469
-
470
- /**
471
- * Get user's private indicators from a 'sessionid' cookie
472
- * @function getPrivateIndicators
473
- * @param {string} session User 'sessionid' cookie
474
- * @param {string} [signature] User 'sessionid_sign' cookie
475
- * @returns {Promise<SearchIndicatorResult[]>} Search results
476
- */
477
- async getPrivateIndicators(session, signature = '') {
478
- const { data } = await axios.get(
479
- 'https://pine-facade.tradingview.com/pine-facade/list',
480
- {
481
- headers: {
482
- cookie: genAuthCookies(session, signature),
483
- },
484
- params: {
485
- filter: 'saved',
486
- },
487
- validateStatus,
488
- },
489
- );
490
-
491
- return data.map((ind) => ({
492
- id: ind.scriptIdPart,
493
- version: ind.version,
494
- name: ind.scriptName,
495
- author: {
496
- id: -1,
497
- username: '@ME@',
498
- },
499
- image: ind.imageUrl,
500
- access: 'private',
501
- source: ind.scriptSource,
502
- type: (ind.extra && ind.extra.kind) ? ind.extra.kind : 'study',
503
- get() {
504
- return module.exports.getIndicator(
505
- ind.scriptIdPart,
506
- ind.version,
507
- session,
508
- signature,
509
- );
510
- },
511
- }));
512
- },
513
-
514
- /**
515
- * User credentials
516
- * @typedef {Object} UserCredentials
517
- * @prop {number} id User ID
518
- * @prop {string} session User session ('sessionid' cookie)
519
- * @prop {string} [signature] User session signature ('sessionid_sign' cookie)
520
- */
521
-
522
- /**
523
- * Get a chart token from a layout ID and the user credentials if the layout is not public
524
- * @function getChartToken
525
- * @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
526
- * @param {UserCredentials} [credentials] User credentials (id + session + [signature])
527
- * @returns {Promise<string>} Token
528
- */
529
- async getChartToken(layout, credentials = {}) {
530
- const { id, session, signature } = (
531
- credentials.id && credentials.session
532
- ? credentials
533
- : { id: -1, session: null, signature: null }
534
- );
535
-
536
- const { data } = await axios.get(
537
- 'https://www.tradingview.com/chart-token',
538
- {
539
- headers: {
540
- cookie: genAuthCookies(session, signature),
541
- },
542
- params: {
543
- image_url: layout,
544
- user_id: id,
545
- },
546
- validateStatus,
547
- },
548
- );
549
-
550
- if (!data.token) throw new Error('Wrong layout or credentials');
551
-
552
- return data.token;
553
- },
554
-
555
- /**
556
- * @typedef {Object} DrawingPoint Drawing poitn
557
- * @prop {number} time_t Point X time position
558
- * @prop {number} price Point Y price position
559
- * @prop {number} offset Point offset
560
- */
561
-
562
- /**
563
- * @typedef {Object} Drawing
564
- * @prop {string} id Drawing ID (Like: 'XXXXXX')
565
- * @prop {string} symbol Layout market symbol (Like: 'BINANCE:BUCEUR')
566
- * @prop {string} ownerSource Owner user ID (Like: 'XXXXXX')
567
- * @prop {string} serverUpdateTime Drawing last update timestamp
568
- * @prop {string} currencyId Currency ID (Like: 'EUR')
569
- * @prop {any} unitId Unit ID
570
- * @prop {string} type Drawing type
571
- * @prop {DrawingPoint[]} points List of drawing points
572
- * @prop {number} zorder Drawing Z order
573
- * @prop {string} linkKey Drawing link key
574
- * @prop {Object} state Drawing state
575
- */
576
-
577
- /**
578
- * Get a chart token from a layout ID and the user credentials if the layout is not public
579
- * @function getDrawings
580
- * @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
581
- * @param {string | ''} [symbol] Market filter (Like: 'BINANCE:BTCEUR')
582
- * @param {UserCredentials} [credentials] User credentials (id + session + [signature])
583
- * @param {number} [chartID] Chart ID
584
- * @returns {Promise<Drawing[]>} Drawings
585
- */
586
- async getDrawings(layout, symbol = '', credentials = {}, chartID = '_shared') {
587
- const chartToken = await module.exports.getChartToken(layout, credentials);
588
-
589
- const { data } = await axios.get(
590
- `https://charts-storage.tradingview.com/charts-storage/get/layout/${
591
- layout
592
- }/sources`,
593
- {
594
- params: {
595
- chart_id: chartID,
596
- jwt: chartToken,
597
- symbol,
598
- },
599
- validateStatus,
600
- },
601
- );
602
-
603
- if (!data.payload) throw new Error('Wrong layout, user credentials, or chart id.');
604
-
605
- return Object.values(data.payload.sources || {}).map((drawing) => ({
606
- ...drawing, ...drawing.state,
607
- }));
608
- },
609
- };
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
- };