@mathieuc/tradingview 3.4.4 → 3.4.5
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/.eslintrc.js +1 -0
- package/package.json +1 -1
- package/src/classes/PinePermManager.js +5 -4
- package/src/miscRequests.js +115 -80
- package/src/utils.js +6 -0
package/.eslintrc.js
CHANGED
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
|
+
const { genAuthCookies } = require('../utils');
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* @typedef {Object} AuthorizationUser
|
|
@@ -50,7 +51,7 @@ class PinePermManager {
|
|
|
50
51
|
headers: {
|
|
51
52
|
origin: 'https://www.tradingview.com',
|
|
52
53
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
53
|
-
cookie:
|
|
54
|
+
cookie: genAuthCookies(this.sessionId, this.signature),
|
|
54
55
|
},
|
|
55
56
|
},
|
|
56
57
|
);
|
|
@@ -84,7 +85,7 @@ class PinePermManager {
|
|
|
84
85
|
headers: {
|
|
85
86
|
origin: 'https://www.tradingview.com',
|
|
86
87
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
87
|
-
cookie:
|
|
88
|
+
cookie: genAuthCookies(this.sessionId, this.signature),
|
|
88
89
|
},
|
|
89
90
|
},
|
|
90
91
|
);
|
|
@@ -118,7 +119,7 @@ class PinePermManager {
|
|
|
118
119
|
headers: {
|
|
119
120
|
origin: 'https://www.tradingview.com',
|
|
120
121
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
121
|
-
cookie:
|
|
122
|
+
cookie: genAuthCookies(this.sessionId, this.signature),
|
|
122
123
|
},
|
|
123
124
|
},
|
|
124
125
|
);
|
|
@@ -143,7 +144,7 @@ class PinePermManager {
|
|
|
143
144
|
headers: {
|
|
144
145
|
origin: 'https://www.tradingview.com',
|
|
145
146
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
146
|
-
cookie:
|
|
147
|
+
cookie: genAuthCookies(this.sessionId, this.signature),
|
|
147
148
|
},
|
|
148
149
|
},
|
|
149
150
|
);
|
package/src/miscRequests.js
CHANGED
|
@@ -2,17 +2,22 @@ const os = require('os');
|
|
|
2
2
|
const axios = require('axios');
|
|
3
3
|
|
|
4
4
|
const PineIndicator = require('./classes/PineIndicator');
|
|
5
|
+
const { genAuthCookies } = require('./utils');
|
|
5
6
|
|
|
6
7
|
const validateStatus = (status) => status < 500;
|
|
7
8
|
|
|
8
9
|
const indicators = ['Recommend.Other', 'Recommend.All', 'Recommend.MA'];
|
|
9
10
|
const builtInIndicList = [];
|
|
10
11
|
|
|
11
|
-
async function fetchScanData(tickers = [],
|
|
12
|
-
const { data } = await axios.post(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
+
);
|
|
16
21
|
|
|
17
22
|
return data;
|
|
18
23
|
}
|
|
@@ -40,56 +45,21 @@ async function fetchScanData(tickers = [], type = '', columns = []) {
|
|
|
40
45
|
* }} Periods
|
|
41
46
|
*/
|
|
42
47
|
|
|
43
|
-
// /**
|
|
44
|
-
// * @typedef {string | 'forex' | 'crypto'
|
|
45
|
-
// * | 'america' | 'australia' | 'canada' | 'egypt'
|
|
46
|
-
// * | 'germany' | 'india' | 'israel' | 'italy'
|
|
47
|
-
// * | 'luxembourg' | 'poland' | 'sweden' | 'turkey'
|
|
48
|
-
// * | 'uk' | 'vietnam'} Screener
|
|
49
|
-
// * You can use `getScreener(exchange)` function for non-forex and non-crypto markets.
|
|
50
|
-
// */
|
|
51
|
-
|
|
52
48
|
module.exports = {
|
|
53
|
-
// /**
|
|
54
|
-
// * Get a screener from an exchange
|
|
55
|
-
// * @function getScreener
|
|
56
|
-
// * @param {string} exchange Example: BINANCE, EURONEXT, NASDAQ
|
|
57
|
-
// * @returns {Screener}
|
|
58
|
-
// */
|
|
59
|
-
// getScreener(exchange) {
|
|
60
|
-
// const e = exchange.toUpperCase();
|
|
61
|
-
// if (['NASDAQ', 'NYSE', 'NYSE ARCA', 'OTC'].includes(e)) return 'america';
|
|
62
|
-
// if (['ASX'].includes(e)) return 'australia';
|
|
63
|
-
// if (['TSX', 'TSXV', 'CSE', 'NEO'].includes(e)) return 'canada';
|
|
64
|
-
// if (['EGX'].includes(e)) return 'egypt';
|
|
65
|
-
// if (['FWB', 'SWB', 'XETR'].includes(e)) return 'germany';
|
|
66
|
-
// if (['BSE', 'NSE'].includes(e)) return 'india';
|
|
67
|
-
// if (['TASE'].includes(e)) return 'israel';
|
|
68
|
-
// if (['MIL', 'MILSEDEX'].includes(e)) return 'italy';
|
|
69
|
-
// if (['LUXSE'].includes(e)) return 'luxembourg';
|
|
70
|
-
// if (['NEWCONNECT'].includes(e)) return 'poland';
|
|
71
|
-
// if (['NGM'].includes(e)) return 'sweden';
|
|
72
|
-
// if (['BIST'].includes(e)) return 'turkey';
|
|
73
|
-
// if (['LSE', 'LSIN'].includes(e)) return 'uk';
|
|
74
|
-
// if (['HNX'].includes(e)) return 'vietnam';
|
|
75
|
-
// return 'global';
|
|
76
|
-
// },
|
|
77
|
-
|
|
78
49
|
/**
|
|
79
50
|
* Get technical analysis
|
|
80
51
|
* @function getTA
|
|
81
|
-
* @param {Screener} screener Market screener
|
|
82
52
|
* @param {string} id Full market id (Example: COINBASE:BTCEUR)
|
|
83
53
|
* @returns {Promise<Periods>} results
|
|
84
54
|
*/
|
|
85
|
-
async getTA(
|
|
55
|
+
async getTA(id) {
|
|
86
56
|
const advice = {};
|
|
87
57
|
|
|
88
58
|
const cols = ['1', '5', '15', '60', '240', '1D', '1W', '1M']
|
|
89
59
|
.map((t) => indicators.map((i) => (t !== '1D' ? `${i}|${t}` : i)))
|
|
90
60
|
.flat();
|
|
91
61
|
|
|
92
|
-
const rs = await fetchScanData([id],
|
|
62
|
+
const rs = await fetchScanData([id], cols);
|
|
93
63
|
if (!rs.data || !rs.data[0]) return false;
|
|
94
64
|
|
|
95
65
|
rs.data[0].d.forEach((val, i) => {
|
|
@@ -107,7 +77,6 @@ module.exports = {
|
|
|
107
77
|
* @prop {string} id Market full symbol
|
|
108
78
|
* @prop {string} exchange Market exchange name
|
|
109
79
|
* @prop {string} fullExchange Market exchange full name
|
|
110
|
-
* @prop {Screener | 'forex' | 'crypto'} screener Market screener
|
|
111
80
|
* @prop {string} symbol Market symbol
|
|
112
81
|
* @prop {string} description Market name
|
|
113
82
|
* @prop {string} type Market type
|
|
@@ -115,7 +84,7 @@ module.exports = {
|
|
|
115
84
|
*/
|
|
116
85
|
|
|
117
86
|
/**
|
|
118
|
-
* Find a symbol
|
|
87
|
+
* Find a symbol (deprecated)
|
|
119
88
|
* @function searchMarket
|
|
120
89
|
* @param {string} search Keywords
|
|
121
90
|
* @param {'stock'
|
|
@@ -123,15 +92,20 @@ module.exports = {
|
|
|
123
92
|
* | 'crypto' | 'index' | 'economic'
|
|
124
93
|
* } [filter] Caterogy filter
|
|
125
94
|
* @returns {Promise<SearchMarketResult[]>} Search results
|
|
95
|
+
* @deprecated Use searchMarketV3 instead
|
|
126
96
|
*/
|
|
127
97
|
async searchMarket(search, filter = '') {
|
|
128
98
|
const { data } = await axios.get(
|
|
129
|
-
|
|
99
|
+
'https://symbol-search.tradingview.com/symbol_search',
|
|
130
100
|
{
|
|
131
|
-
|
|
101
|
+
params: {
|
|
102
|
+
text: search.replace(/ /g, '%20'),
|
|
103
|
+
type: filter,
|
|
104
|
+
},
|
|
132
105
|
headers: {
|
|
133
106
|
origin: 'https://www.tradingview.com',
|
|
134
107
|
},
|
|
108
|
+
validateStatus,
|
|
135
109
|
},
|
|
136
110
|
);
|
|
137
111
|
|
|
@@ -139,21 +113,63 @@ module.exports = {
|
|
|
139
113
|
const exchange = s.exchange.split(' ')[0];
|
|
140
114
|
const id = `${exchange}:${s.symbol}`;
|
|
141
115
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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}`;
|
|
147
164
|
|
|
148
165
|
return {
|
|
149
166
|
id,
|
|
150
167
|
exchange,
|
|
151
168
|
fullExchange: s.exchange,
|
|
152
|
-
screener,
|
|
153
169
|
symbol: s.symbol,
|
|
154
170
|
description: s.description,
|
|
155
171
|
type: s.type,
|
|
156
|
-
getTA: () => this.getTA(
|
|
172
|
+
getTA: () => this.getTA(id),
|
|
157
173
|
};
|
|
158
174
|
});
|
|
159
175
|
},
|
|
@@ -182,16 +198,26 @@ module.exports = {
|
|
|
182
198
|
if (!builtInIndicList.length) {
|
|
183
199
|
await Promise.all(['standard', 'candlestick', 'fundamental'].map(async (type) => {
|
|
184
200
|
const { data } = await axios.get(
|
|
185
|
-
|
|
186
|
-
{
|
|
201
|
+
'https://pine-facade.tradingview.com/pine-facade/list',
|
|
202
|
+
{
|
|
203
|
+
params: {
|
|
204
|
+
filter: type,
|
|
205
|
+
},
|
|
206
|
+
validateStatus,
|
|
207
|
+
},
|
|
187
208
|
);
|
|
188
209
|
builtInIndicList.push(...data);
|
|
189
210
|
}));
|
|
190
211
|
}
|
|
191
212
|
|
|
192
213
|
const { data } = await axios.get(
|
|
193
|
-
|
|
194
|
-
{
|
|
214
|
+
'https://www.tradingview.com/pubscripts-suggest-json',
|
|
215
|
+
{
|
|
216
|
+
params: {
|
|
217
|
+
search: search.replace(/ /g, '%20'),
|
|
218
|
+
},
|
|
219
|
+
validateStatus,
|
|
220
|
+
},
|
|
195
221
|
);
|
|
196
222
|
|
|
197
223
|
function norm(str = '') {
|
|
@@ -253,10 +279,10 @@ module.exports = {
|
|
|
253
279
|
const { data } = await axios.get(
|
|
254
280
|
`https://pine-facade.tradingview.com/pine-facade/translate/${indicID}/${version}`,
|
|
255
281
|
{
|
|
256
|
-
validateStatus,
|
|
257
282
|
headers: {
|
|
258
|
-
cookie:
|
|
283
|
+
cookie: genAuthCookies(session, signature),
|
|
259
284
|
},
|
|
285
|
+
validateStatus,
|
|
260
286
|
},
|
|
261
287
|
);
|
|
262
288
|
|
|
@@ -356,12 +382,12 @@ module.exports = {
|
|
|
356
382
|
'https://www.tradingview.com/accounts/signin/',
|
|
357
383
|
`username=${username}&password=${password}${remember ? '&remember=on' : ''}`,
|
|
358
384
|
{
|
|
359
|
-
validateStatus,
|
|
360
385
|
headers: {
|
|
361
386
|
referer: 'https://www.tradingview.com',
|
|
362
387
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
363
388
|
'User-agent': `${UA} (${os.version()}; ${os.platform()}; ${os.arch()})`,
|
|
364
389
|
},
|
|
390
|
+
validateStatus,
|
|
365
391
|
},
|
|
366
392
|
);
|
|
367
393
|
|
|
@@ -403,10 +429,10 @@ module.exports = {
|
|
|
403
429
|
*/
|
|
404
430
|
async getUser(session, signature = '', location = 'https://www.tradingview.com/') {
|
|
405
431
|
const { data } = await axios.get(location, {
|
|
406
|
-
validateStatus,
|
|
407
432
|
headers: {
|
|
408
|
-
cookie:
|
|
433
|
+
cookie: genAuthCookies(session, signature),
|
|
409
434
|
},
|
|
435
|
+
validateStatus,
|
|
410
436
|
});
|
|
411
437
|
|
|
412
438
|
if (data.includes('auth_token')) {
|
|
@@ -442,12 +468,18 @@ module.exports = {
|
|
|
442
468
|
* @returns {Promise<SearchIndicatorResult[]>} Search results
|
|
443
469
|
*/
|
|
444
470
|
async getPrivateIndicators(session, signature = '') {
|
|
445
|
-
const { data } = await axios.get(
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
471
|
+
const { data } = await axios.get(
|
|
472
|
+
'https://pine-facade.tradingview.com/pine-facade/list',
|
|
473
|
+
{
|
|
474
|
+
headers: {
|
|
475
|
+
cookie: genAuthCookies(session, signature),
|
|
476
|
+
},
|
|
477
|
+
params: {
|
|
478
|
+
filter: 'saved',
|
|
479
|
+
},
|
|
480
|
+
validateStatus,
|
|
449
481
|
},
|
|
450
|
-
|
|
482
|
+
);
|
|
451
483
|
|
|
452
484
|
return data.map((ind) => ({
|
|
453
485
|
id: ind.scriptIdPart,
|
|
@@ -495,14 +527,16 @@ module.exports = {
|
|
|
495
527
|
);
|
|
496
528
|
|
|
497
529
|
const { data } = await axios.get(
|
|
498
|
-
|
|
530
|
+
'https://www.tradingview.com/chart-token',
|
|
499
531
|
{
|
|
500
|
-
validateStatus,
|
|
501
532
|
headers: {
|
|
502
|
-
cookie: session
|
|
503
|
-
? `sessionid=${session}${signature ? `;sessionid_sign=${signature};` : ''}`
|
|
504
|
-
: '',
|
|
533
|
+
cookie: genAuthCookies(session, signature),
|
|
505
534
|
},
|
|
535
|
+
params: {
|
|
536
|
+
image_url: layout,
|
|
537
|
+
user_id: id,
|
|
538
|
+
},
|
|
539
|
+
validateStatus,
|
|
506
540
|
},
|
|
507
541
|
);
|
|
508
542
|
|
|
@@ -548,14 +582,15 @@ module.exports = {
|
|
|
548
582
|
const { data } = await axios.get(
|
|
549
583
|
`https://charts-storage.tradingview.com/charts-storage/get/layout/${
|
|
550
584
|
layout
|
|
551
|
-
}/sources
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
585
|
+
}/sources`,
|
|
586
|
+
{
|
|
587
|
+
params: {
|
|
588
|
+
chart_id: chartID,
|
|
589
|
+
jwt: chartToken,
|
|
590
|
+
symbol,
|
|
591
|
+
},
|
|
592
|
+
validateStatus,
|
|
593
|
+
},
|
|
559
594
|
);
|
|
560
595
|
|
|
561
596
|
if (!data.payload) throw new Error('Wrong layout, user credentials, or chart id.');
|
package/src/utils.js
CHANGED
|
@@ -11,4 +11,10 @@ module.exports = {
|
|
|
11
11
|
for (let i = 0; i < 12; i += 1) r += c.charAt(Math.floor(Math.random() * c.length));
|
|
12
12
|
return `${type}_${r}`;
|
|
13
13
|
},
|
|
14
|
+
|
|
15
|
+
genAuthCookies(sessionId = '', signature = '') {
|
|
16
|
+
if (!sessionId) return '';
|
|
17
|
+
if (!signature) return `sessionid=${sessionId}`;
|
|
18
|
+
return `sessionid=${sessionId};sessionid_sign=${signature}`;
|
|
19
|
+
},
|
|
14
20
|
};
|