@mathieuc/tradingview 3.4.3 → 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 +128 -81
- 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 = '') {
|
|
@@ -243,14 +269,21 @@ module.exports = {
|
|
|
243
269
|
* @function getIndicator
|
|
244
270
|
* @param {string} id Indicator ID (Like: PUB;XXXXXXXXXXXXXXXXXXXXX)
|
|
245
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
|
|
246
274
|
* @returns {Promise<PineIndicator>} Indicator
|
|
247
275
|
*/
|
|
248
|
-
async getIndicator(id, version = 'last') {
|
|
276
|
+
async getIndicator(id, version = 'last', session = '', signature = '') {
|
|
249
277
|
const indicID = id.replace(/ |%/g, '%25');
|
|
250
278
|
|
|
251
279
|
const { data } = await axios.get(
|
|
252
280
|
`https://pine-facade.tradingview.com/pine-facade/translate/${indicID}/${version}`,
|
|
253
|
-
{
|
|
281
|
+
{
|
|
282
|
+
headers: {
|
|
283
|
+
cookie: genAuthCookies(session, signature),
|
|
284
|
+
},
|
|
285
|
+
validateStatus,
|
|
286
|
+
},
|
|
254
287
|
);
|
|
255
288
|
|
|
256
289
|
if (!data.success || !data.result.metaInfo || !data.result.metaInfo.inputs) {
|
|
@@ -349,12 +382,12 @@ module.exports = {
|
|
|
349
382
|
'https://www.tradingview.com/accounts/signin/',
|
|
350
383
|
`username=${username}&password=${password}${remember ? '&remember=on' : ''}`,
|
|
351
384
|
{
|
|
352
|
-
validateStatus,
|
|
353
385
|
headers: {
|
|
354
386
|
referer: 'https://www.tradingview.com',
|
|
355
387
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
356
388
|
'User-agent': `${UA} (${os.version()}; ${os.platform()}; ${os.arch()})`,
|
|
357
389
|
},
|
|
390
|
+
validateStatus,
|
|
358
391
|
},
|
|
359
392
|
);
|
|
360
393
|
|
|
@@ -396,10 +429,10 @@ module.exports = {
|
|
|
396
429
|
*/
|
|
397
430
|
async getUser(session, signature = '', location = 'https://www.tradingview.com/') {
|
|
398
431
|
const { data } = await axios.get(location, {
|
|
399
|
-
validateStatus,
|
|
400
432
|
headers: {
|
|
401
|
-
cookie:
|
|
433
|
+
cookie: genAuthCookies(session, signature),
|
|
402
434
|
},
|
|
435
|
+
validateStatus,
|
|
403
436
|
});
|
|
404
437
|
|
|
405
438
|
if (data.includes('auth_token')) {
|
|
@@ -435,12 +468,18 @@ module.exports = {
|
|
|
435
468
|
* @returns {Promise<SearchIndicatorResult[]>} Search results
|
|
436
469
|
*/
|
|
437
470
|
async getPrivateIndicators(session, signature = '') {
|
|
438
|
-
const { data } = await axios.get(
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
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,
|
|
442
481
|
},
|
|
443
|
-
|
|
482
|
+
);
|
|
444
483
|
|
|
445
484
|
return data.map((ind) => ({
|
|
446
485
|
id: ind.scriptIdPart,
|
|
@@ -455,7 +494,12 @@ module.exports = {
|
|
|
455
494
|
source: ind.scriptSource,
|
|
456
495
|
type: (ind.extra && ind.extra.kind) ? ind.extra.kind : 'study',
|
|
457
496
|
get() {
|
|
458
|
-
return module.exports.getIndicator(
|
|
497
|
+
return module.exports.getIndicator(
|
|
498
|
+
ind.scriptIdPart,
|
|
499
|
+
ind.version,
|
|
500
|
+
session,
|
|
501
|
+
signature,
|
|
502
|
+
);
|
|
459
503
|
},
|
|
460
504
|
}));
|
|
461
505
|
},
|
|
@@ -483,14 +527,16 @@ module.exports = {
|
|
|
483
527
|
);
|
|
484
528
|
|
|
485
529
|
const { data } = await axios.get(
|
|
486
|
-
|
|
530
|
+
'https://www.tradingview.com/chart-token',
|
|
487
531
|
{
|
|
488
|
-
validateStatus,
|
|
489
532
|
headers: {
|
|
490
|
-
cookie: session
|
|
491
|
-
? `sessionid=${session}${signature ? `;sessionid_sign=${signature};` : ''}`
|
|
492
|
-
: '',
|
|
533
|
+
cookie: genAuthCookies(session, signature),
|
|
493
534
|
},
|
|
535
|
+
params: {
|
|
536
|
+
image_url: layout,
|
|
537
|
+
user_id: id,
|
|
538
|
+
},
|
|
539
|
+
validateStatus,
|
|
494
540
|
},
|
|
495
541
|
);
|
|
496
542
|
|
|
@@ -536,14 +582,15 @@ module.exports = {
|
|
|
536
582
|
const { data } = await axios.get(
|
|
537
583
|
`https://charts-storage.tradingview.com/charts-storage/get/layout/${
|
|
538
584
|
layout
|
|
539
|
-
}/sources
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
585
|
+
}/sources`,
|
|
586
|
+
{
|
|
587
|
+
params: {
|
|
588
|
+
chart_id: chartID,
|
|
589
|
+
jwt: chartToken,
|
|
590
|
+
symbol,
|
|
591
|
+
},
|
|
592
|
+
validateStatus,
|
|
593
|
+
},
|
|
547
594
|
);
|
|
548
595
|
|
|
549
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
|
};
|