@mathieuc/tradingview 3.0.0 → 3.3.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.
- package/.eslintrc.js +6 -0
- package/README.md +29 -3
- package/docs/DOCS.md +3 -0
- package/examples/AllPrivateIndicators.js +4 -4
- package/examples/BuiltInIndicator.js +1 -1
- package/examples/CustomChartType.js +1 -0
- package/examples/Errors.js +147 -153
- package/examples/FakeReplayMode.js +41 -0
- package/examples/FromToData.js +29 -0
- package/examples/GetDrawings.js +26 -0
- package/examples/GraphicIndicator.js +7 -5
- package/examples/PinePermManage.js +57 -0
- package/examples/ReplayMode.js +97 -0
- package/examples/UserLogin.js +16 -0
- package/main.js +2 -0
- package/package.json +6 -9
- package/src/FormData.js +36 -0
- package/src/chart/session.js +205 -24
- package/src/chart/study.js +68 -68
- package/src/classes/BuiltInIndicator.js +7 -1
- package/src/classes/PineIndicator.js +7 -7
- package/src/classes/PinePermManager.js +143 -0
- package/src/client.js +15 -10
- package/src/miscRequests.js +144 -101
- package/src/protocol.js +7 -1
- package/src/quote/session.js +1 -0
- package/src/request.js +37 -0
- package/src/types.js +6 -2
- package/src/utils.js +6 -0
- package/test.js +58 -147
- package/tests/1. Search.js +18 -0
- package/tests/2. QuoteSession.js +54 -0
- package/tests/3. SimpleChart.js +61 -0
- package/tests/4. Indicators.js +100 -0
- package/tests/5. BuiltInIndicator.js +41 -0
- package/tests/6. FakeReplayMode.js +59 -0
- package/tests/7. ReplayMode.js +51 -0
- package/tests/8. CustomChartTypes.js +115 -0
- package/tests/9. AllErrors.js +146 -0
- package/.github/FUNDING.yml +0 -1
- package/examples/_RenkoIndicator.js +0 -41
- package/tests/alerts/discordWH.js +0 -76
- package/tests/alerts/drawings.js +0 -41
- package/tests/alerts/envLoader.js +0 -11
- package/tests/alerts/manualAlert.js +0 -77
- package/tests/alerts/sentNotifs.js +0 -16
- package/tests/alerts/strategyAlert.js +0 -94
- package/tests/analysis.js +0 -13
- package/tests/indicator.js +0 -42
- package/tests/prices.js +0 -33
- package/tests/strategy.js +0 -56
package/src/miscRequests.js
CHANGED
|
@@ -1,45 +1,16 @@
|
|
|
1
|
+
const os = require('os');
|
|
1
2
|
const https = require('https');
|
|
3
|
+
const request = require('./request');
|
|
4
|
+
const FormData = require('./FormData');
|
|
2
5
|
|
|
6
|
+
const PinePermManager = require('./classes/PinePermManager');
|
|
3
7
|
const PineIndicator = require('./classes/PineIndicator');
|
|
4
8
|
|
|
5
9
|
const indicators = ['Recommend.Other', 'Recommend.All', 'Recommend.MA'];
|
|
6
10
|
const builtInIndicList = [];
|
|
7
11
|
|
|
8
|
-
/**
|
|
9
|
-
* @param {https.RequestOptions} options HTTPS Request options
|
|
10
|
-
* @param {boolean} [raw] Get raw or JSON data
|
|
11
|
-
* @param {string} [content] Request body content
|
|
12
|
-
* @returns {Promise<string | object | array>} Result
|
|
13
|
-
*/
|
|
14
|
-
function request(options = {}, raw = false, content = '') {
|
|
15
|
-
return new Promise((cb, err) => {
|
|
16
|
-
const req = https.request(options, (res) => {
|
|
17
|
-
let data = '';
|
|
18
|
-
res.on('data', (c) => { data += c; });
|
|
19
|
-
res.on('end', () => {
|
|
20
|
-
if (raw) {
|
|
21
|
-
cb(data);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
data = JSON.parse(data);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
err(new Error('Can\'t parse server response'));
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
cb(data);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
req.on('error', err);
|
|
37
|
-
req.end(content);
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
12
|
async function fetchScanData(tickers = [], type = '', columns = []) {
|
|
42
|
-
let data = await request({
|
|
13
|
+
let { data } = await request({
|
|
43
14
|
method: 'POST',
|
|
44
15
|
hostname: 'scanner.tradingview.com',
|
|
45
16
|
path: `/${type}/scan`,
|
|
@@ -59,11 +30,17 @@ async function fetchScanData(tickers = [], type = '', columns = []) {
|
|
|
59
30
|
return data;
|
|
60
31
|
}
|
|
61
32
|
|
|
33
|
+
/** @typedef {number} advice */
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @typedef {{
|
|
37
|
+
* Other: advice,
|
|
38
|
+
* All: advice,
|
|
39
|
+
* MA: advice
|
|
40
|
+
* }} Period
|
|
41
|
+
*/
|
|
42
|
+
|
|
62
43
|
/**
|
|
63
|
-
* @typedef {number} advice
|
|
64
|
-
*
|
|
65
|
-
* @typedef {{ Other: advice, All: advice, MA: advice }} Period
|
|
66
|
-
*
|
|
67
44
|
* @typedef {{
|
|
68
45
|
* '1': Period,
|
|
69
46
|
* '5': Period,
|
|
@@ -72,21 +49,25 @@ async function fetchScanData(tickers = [], type = '', columns = []) {
|
|
|
72
49
|
* '240': Period,
|
|
73
50
|
* '1D': Period,
|
|
74
51
|
* '1W': Period,
|
|
75
|
-
* '1M': Period
|
|
52
|
+
* '1M': Period
|
|
76
53
|
* }} Periods
|
|
77
|
-
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
/**
|
|
78
57
|
* @typedef {string | 'forex' | 'crypto'
|
|
79
58
|
* | 'america' | 'australia' | 'canada' | 'egypt'
|
|
80
59
|
* | 'germany' | 'india' | 'israel' | 'italy'
|
|
81
60
|
* | 'luxembourg' | 'poland' | 'sweden' | 'turkey'
|
|
82
|
-
* | 'uk' | 'vietnam'}
|
|
61
|
+
* | 'uk' | 'vietnam'} Screener
|
|
83
62
|
* You can use `getScreener(exchange)` function for non-forex and non-crypto markets.
|
|
84
63
|
*/
|
|
85
64
|
|
|
86
65
|
module.exports = {
|
|
87
66
|
/**
|
|
67
|
+
* Get a screener from an exchange
|
|
68
|
+
* @function getScreener
|
|
88
69
|
* @param {string} exchange Example: BINANCE, EURONEXT, NASDAQ
|
|
89
|
-
* @returns {
|
|
70
|
+
* @returns {Screener}
|
|
90
71
|
*/
|
|
91
72
|
getScreener(exchange) {
|
|
92
73
|
const e = exchange.toUpperCase();
|
|
@@ -109,7 +90,8 @@ module.exports = {
|
|
|
109
90
|
|
|
110
91
|
/**
|
|
111
92
|
* Get technical analysis
|
|
112
|
-
* @
|
|
93
|
+
* @function getTA
|
|
94
|
+
* @param {Screener} screener Market screener
|
|
113
95
|
* @param {string} id Full market id (Example: COINBASE:BTCEUR)
|
|
114
96
|
* @returns {Promise<Periods>} results
|
|
115
97
|
*/
|
|
@@ -135,24 +117,28 @@ module.exports = {
|
|
|
135
117
|
|
|
136
118
|
/**
|
|
137
119
|
* @typedef {Object} SearchMarketResult
|
|
138
|
-
* @
|
|
139
|
-
* @
|
|
140
|
-
* @
|
|
141
|
-
* @
|
|
142
|
-
* @
|
|
143
|
-
* @
|
|
144
|
-
* @
|
|
145
|
-
* @
|
|
120
|
+
* @prop {string} id Market full symbol
|
|
121
|
+
* @prop {string} exchange Market exchange name
|
|
122
|
+
* @prop {string} fullExchange Market exchange full name
|
|
123
|
+
* @prop {Screener | 'forex' | 'crypto'} screener Market screener
|
|
124
|
+
* @prop {string} symbol Market symbol
|
|
125
|
+
* @prop {string} description Market name
|
|
126
|
+
* @prop {string} type Market type
|
|
127
|
+
* @prop {() => Promise<Periods>} getTA Get market technical analysis
|
|
146
128
|
*/
|
|
147
129
|
|
|
148
130
|
/**
|
|
149
131
|
* Find a symbol
|
|
132
|
+
* @function searchMarket
|
|
150
133
|
* @param {string} search Keywords
|
|
151
|
-
* @param {'stock'
|
|
134
|
+
* @param {'stock'
|
|
135
|
+
* | 'futures' | 'forex' | 'cfd'
|
|
136
|
+
* | 'crypto' | 'index' | 'economic'
|
|
137
|
+
* } [filter] Caterogy filter
|
|
152
138
|
* @returns {Promise<SearchMarketResult[]>} Search results
|
|
153
139
|
*/
|
|
154
140
|
async searchMarket(search, filter = '') {
|
|
155
|
-
const data = await request({
|
|
141
|
+
const { data } = await request({
|
|
156
142
|
host: 'symbol-search.tradingview.com',
|
|
157
143
|
path: `/symbol_search/?text=${search.replace(/ /g, '%20')}&type=${filter}`,
|
|
158
144
|
origin: 'https://www.tradingview.com',
|
|
@@ -182,34 +168,35 @@ module.exports = {
|
|
|
182
168
|
|
|
183
169
|
/**
|
|
184
170
|
* @typedef {Object} SearchIndicatorResult
|
|
185
|
-
* @
|
|
186
|
-
* @
|
|
187
|
-
* @
|
|
188
|
-
* @
|
|
189
|
-
* @
|
|
190
|
-
* @
|
|
191
|
-
* @
|
|
192
|
-
* @
|
|
171
|
+
* @prop {string} id Script ID
|
|
172
|
+
* @prop {string} version Script version
|
|
173
|
+
* @prop {string} name Script complete name
|
|
174
|
+
* @prop {{ id: number, username: string }} author Author user ID
|
|
175
|
+
* @prop {string} image Image ID https://tradingview.com/i/${image}
|
|
176
|
+
* @prop {string | ''} source Script source (if available)
|
|
177
|
+
* @prop {'study' | 'strategy'} type Script type (study / strategy)
|
|
178
|
+
* @prop {'open_source' | 'closed_source' | 'invite_only'
|
|
193
179
|
* | 'private' | 'other'} access Script access type
|
|
194
|
-
* @
|
|
180
|
+
* @prop {() => Promise<PineIndicator>} get Get the full indicator informations
|
|
195
181
|
*/
|
|
196
182
|
|
|
197
183
|
/**
|
|
198
184
|
* Find an indicator
|
|
185
|
+
* @function searchIndicator
|
|
199
186
|
* @param {string} search Keywords
|
|
200
187
|
* @returns {Promise<SearchIndicatorResult[]>} Search results
|
|
201
188
|
*/
|
|
202
189
|
async searchIndicator(search = '') {
|
|
203
190
|
if (!builtInIndicList.length) {
|
|
204
191
|
await Promise.all(['standard', 'candlestick', 'fundamental'].map(async (type) => {
|
|
205
|
-
builtInIndicList.push(...await request({
|
|
192
|
+
builtInIndicList.push(...(await request({
|
|
206
193
|
host: 'pine-facade.tradingview.com',
|
|
207
194
|
path: `/pine-facade/list/?filter=${type}`,
|
|
208
|
-
}));
|
|
195
|
+
})).data);
|
|
209
196
|
}));
|
|
210
197
|
}
|
|
211
198
|
|
|
212
|
-
const data = await request({
|
|
199
|
+
const { data } = await request({
|
|
213
200
|
host: 'www.tradingview.com',
|
|
214
201
|
path: `/pubscripts-suggest-json/?search=${search.replace(/ /g, '%20')}`,
|
|
215
202
|
});
|
|
@@ -260,6 +247,7 @@ module.exports = {
|
|
|
260
247
|
|
|
261
248
|
/**
|
|
262
249
|
* Get an indicator
|
|
250
|
+
* @function getIndicator
|
|
263
251
|
* @param {string} id Indicator ID (Like: PUB;XXXXXXXXXXXXXXXXXXXXX)
|
|
264
252
|
* @param {'last' | string} [version] Wanted version of the indicator
|
|
265
253
|
* @returns {Promise<PineIndicator>} Indicator
|
|
@@ -267,7 +255,7 @@ module.exports = {
|
|
|
267
255
|
async getIndicator(id, version = 'last') {
|
|
268
256
|
const indicID = id.replace(/ |%/g, '%25');
|
|
269
257
|
|
|
270
|
-
let data = await request({
|
|
258
|
+
let { data } = await request({
|
|
271
259
|
host: 'pine-facade.tradingview.com',
|
|
272
260
|
path: `/pine-facade/translate/${indicID}/${version}`,
|
|
273
261
|
}, true);
|
|
@@ -340,25 +328,74 @@ module.exports = {
|
|
|
340
328
|
|
|
341
329
|
/**
|
|
342
330
|
* @typedef {Object} User Instance of User
|
|
343
|
-
* @
|
|
344
|
-
* @
|
|
345
|
-
* @
|
|
346
|
-
* @
|
|
347
|
-
* @
|
|
348
|
-
* @
|
|
349
|
-
* @
|
|
350
|
-
* @
|
|
351
|
-
* @
|
|
352
|
-
* @
|
|
353
|
-
* @
|
|
354
|
-
* @
|
|
355
|
-
* @
|
|
356
|
-
* @
|
|
357
|
-
* @
|
|
331
|
+
* @prop {number} id User ID
|
|
332
|
+
* @prop {string} username User username
|
|
333
|
+
* @prop {string} firstName User first name
|
|
334
|
+
* @prop {string} lastName User last name
|
|
335
|
+
* @prop {number} reputation User reputation
|
|
336
|
+
* @prop {number} following Number of following accounts
|
|
337
|
+
* @prop {number} followers Number of followers
|
|
338
|
+
* @prop {Object} notifications User's notifications
|
|
339
|
+
* @prop {number} notifications.user User notifications
|
|
340
|
+
* @prop {number} notifications.following Notification from following accounts
|
|
341
|
+
* @prop {string} session User session
|
|
342
|
+
* @prop {string} sessionHash User session hash
|
|
343
|
+
* @prop {string} privateChannel User private channel
|
|
344
|
+
* @prop {string} authToken User auth token
|
|
345
|
+
* @prop {Date} joinDate Account creation date
|
|
346
|
+
*/
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Get user and sessionid from username/email and password
|
|
350
|
+
* @function loginUser
|
|
351
|
+
* @param {string} username User username/email
|
|
352
|
+
* @param {string} password User password
|
|
353
|
+
* @param {boolean} [remember] Remember the session (default: false)
|
|
354
|
+
* @param {string} [UA] Custom UserAgent
|
|
355
|
+
* @returns {Promise<User>} Token
|
|
358
356
|
*/
|
|
357
|
+
async loginUser(username, password, remember = true, UA = 'TWAPI/3.0') {
|
|
358
|
+
const formData = new FormData();
|
|
359
|
+
formData.append('username', username);
|
|
360
|
+
formData.append('password', password);
|
|
361
|
+
if (remember) formData.append('remember', 'on');
|
|
362
|
+
|
|
363
|
+
const { data, cookies } = await request({
|
|
364
|
+
method: 'POST',
|
|
365
|
+
host: 'www.tradingview.com',
|
|
366
|
+
path: '/accounts/signin/',
|
|
367
|
+
headers: {
|
|
368
|
+
referer: 'https://www.tradingview.com',
|
|
369
|
+
'Content-Type': `multipart/form-data; boundary=${formData.boundary}`,
|
|
370
|
+
'User-agent': `${UA} (${os.version()}; ${os.platform()}; ${os.arch()})`,
|
|
371
|
+
},
|
|
372
|
+
}, false, formData.toString());
|
|
373
|
+
|
|
374
|
+
if (data.error) throw new Error(data.error);
|
|
375
|
+
|
|
376
|
+
const cookie = cookies.find((c) => c.includes('sessionid='));
|
|
377
|
+
const session = (cookie.match(/sessionid=(.*?);/) ?? [])[1];
|
|
378
|
+
|
|
379
|
+
return {
|
|
380
|
+
id: data.user.id,
|
|
381
|
+
username: data.user.username,
|
|
382
|
+
firstName: data.user.first_name,
|
|
383
|
+
lastName: data.user.last_name,
|
|
384
|
+
reputation: data.user.reputation,
|
|
385
|
+
following: data.user.following,
|
|
386
|
+
followers: data.user.followers,
|
|
387
|
+
notifications: data.user.notification_count,
|
|
388
|
+
session,
|
|
389
|
+
sessionHash: data.user.session_hash,
|
|
390
|
+
privateChannel: data.user.private_channel,
|
|
391
|
+
authToken: data.user.auth_token,
|
|
392
|
+
joinDate: new Date(data.user.date_joined),
|
|
393
|
+
};
|
|
394
|
+
},
|
|
359
395
|
|
|
360
396
|
/**
|
|
361
|
-
* Get
|
|
397
|
+
* Get user from 'sessionid' cookie
|
|
398
|
+
* @function getUser
|
|
362
399
|
* @param {string} session User 'sessionid' cookie
|
|
363
400
|
* @param {string} [location] Auth page location (For france: https://fr.tradingview.com/)
|
|
364
401
|
* @returns {Promise<User>} Token
|
|
@@ -404,6 +441,7 @@ module.exports = {
|
|
|
404
441
|
|
|
405
442
|
/**
|
|
406
443
|
* Get user's private indicators from a 'sessionid' cookie
|
|
444
|
+
* @function getPrivateIndicators
|
|
407
445
|
* @param {string} session User 'sessionid' cookie
|
|
408
446
|
* @returns {Promise<SearchIndicatorResult[]>} Search results
|
|
409
447
|
*/
|
|
@@ -437,6 +475,9 @@ module.exports = {
|
|
|
437
475
|
get() {
|
|
438
476
|
return module.exports.getIndicator(ind.scriptIdPart, ind.version);
|
|
439
477
|
},
|
|
478
|
+
getManager() {
|
|
479
|
+
return new PinePermManager(ind.scriptIdPart);
|
|
480
|
+
},
|
|
440
481
|
})));
|
|
441
482
|
});
|
|
442
483
|
|
|
@@ -448,12 +489,13 @@ module.exports = {
|
|
|
448
489
|
/**
|
|
449
490
|
* User credentials
|
|
450
491
|
* @typedef {Object} UserCredentials
|
|
451
|
-
* @
|
|
452
|
-
* @
|
|
492
|
+
* @prop {number} id User ID
|
|
493
|
+
* @prop {string} session User session ('sessionid' cookie)
|
|
453
494
|
*/
|
|
454
495
|
|
|
455
496
|
/**
|
|
456
497
|
* Get a chart token from a layout ID and the user credentials if the layout is not public
|
|
498
|
+
* @function getChartToken
|
|
457
499
|
* @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
|
|
458
500
|
* @param {UserCredentials} [credentials] User credentials (id + session)
|
|
459
501
|
* @returns {Promise<string>} Token
|
|
@@ -463,7 +505,7 @@ module.exports = {
|
|
|
463
505
|
const userID = creds ? credentials.id : -1;
|
|
464
506
|
const session = creds ? credentials.session : null;
|
|
465
507
|
|
|
466
|
-
const data = await request({
|
|
508
|
+
const { data } = await request({
|
|
467
509
|
host: 'www.tradingview.com',
|
|
468
510
|
path: `/chart-token/?image_url=${layout}&user_id=${userID}`,
|
|
469
511
|
headers: { cookie: session ? `sessionid=${session}` : '' },
|
|
@@ -476,32 +518,33 @@ module.exports = {
|
|
|
476
518
|
|
|
477
519
|
/**
|
|
478
520
|
* @typedef {Object} DrawingPoint Drawing poitn
|
|
479
|
-
* @
|
|
480
|
-
* @
|
|
481
|
-
* @
|
|
521
|
+
* @prop {number} time_t Point X time position
|
|
522
|
+
* @prop {number} price Point Y price position
|
|
523
|
+
* @prop {number} offset Point offset
|
|
482
524
|
*/
|
|
483
525
|
|
|
484
526
|
/**
|
|
485
527
|
* @typedef {Object} Drawing
|
|
486
|
-
* @
|
|
487
|
-
* @
|
|
488
|
-
* @
|
|
489
|
-
* @
|
|
490
|
-
* @
|
|
491
|
-
* @
|
|
492
|
-
* @
|
|
493
|
-
* @
|
|
494
|
-
* @
|
|
495
|
-
* @
|
|
496
|
-
* @
|
|
528
|
+
* @prop {string} id Drawing ID (Like: 'XXXXXX')
|
|
529
|
+
* @prop {string} symbol Layout market symbol (Like: 'BINANCE:BUCEUR')
|
|
530
|
+
* @prop {string} ownerSource Owner user ID (Like: 'XXXXXX')
|
|
531
|
+
* @prop {string} serverUpdateTime Drawing last update timestamp
|
|
532
|
+
* @prop {string} currencyId Currency ID (Like: 'EUR')
|
|
533
|
+
* @prop {any} unitId Unit ID
|
|
534
|
+
* @prop {string} type Drawing type
|
|
535
|
+
* @prop {DrawingPoint[]} points List of drawing points
|
|
536
|
+
* @prop {number} zorder Drawing Z order
|
|
537
|
+
* @prop {string} linkKey Drawing link key
|
|
538
|
+
* @prop {Object} state Drawing state
|
|
497
539
|
*/
|
|
498
540
|
|
|
499
541
|
/**
|
|
500
542
|
* Get a chart token from a layout ID and the user credentials if the layout is not public
|
|
543
|
+
* @function getDrawings
|
|
501
544
|
* @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
|
|
502
545
|
* @param {string | ''} [symbol] Market filter (Like: 'BINANCE:BTCEUR')
|
|
503
546
|
* @param {UserCredentials} [credentials] User credentials (id + session)
|
|
504
|
-
* @param {number} [chartID
|
|
547
|
+
* @param {number} [chartID] Chart ID
|
|
505
548
|
* @returns {Promise<Drawing[]>} Drawings
|
|
506
549
|
*/
|
|
507
550
|
async getDrawings(layout, symbol = '', credentials = {}, chartID = 1) {
|
|
@@ -509,7 +552,7 @@ module.exports = {
|
|
|
509
552
|
const creds = credentials.id && credentials.session;
|
|
510
553
|
const session = creds ? credentials.session : null;
|
|
511
554
|
|
|
512
|
-
const data = await request({
|
|
555
|
+
const { data } = await request({
|
|
513
556
|
host: 'charts-storage.tradingview.com',
|
|
514
557
|
path: `/charts-storage/layout/${layout}/sources?chart_id=${chartID
|
|
515
558
|
}&jwt=${chartToken}${symbol ? `&symbol=${symbol}` : ''}`,
|
package/src/protocol.js
CHANGED
|
@@ -6,14 +6,18 @@ const JSZip = require('jszip');
|
|
|
6
6
|
* @prop {[session: string, {}]} [p] Packet data
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
const cleanerRgx = /~h~/g;
|
|
10
|
+
const splitterRgx = /~m~[0-9]{1,}~m~/g;
|
|
11
|
+
|
|
9
12
|
module.exports = {
|
|
10
13
|
/**
|
|
11
14
|
* Parse websocket packet
|
|
15
|
+
* @function parseWSPacket
|
|
12
16
|
* @param {string} str Websocket raw data
|
|
13
17
|
* @returns {TWPacket[]} TradingView packets
|
|
14
18
|
*/
|
|
15
19
|
parseWSPacket(str) {
|
|
16
|
-
return str.replace(
|
|
20
|
+
return str.replace(cleanerRgx, '').split(splitterRgx)
|
|
17
21
|
.map((p) => {
|
|
18
22
|
if (!p) return false;
|
|
19
23
|
try {
|
|
@@ -28,6 +32,7 @@ module.exports = {
|
|
|
28
32
|
|
|
29
33
|
/**
|
|
30
34
|
* Format websocket packet
|
|
35
|
+
* @function formatWSPacket
|
|
31
36
|
* @param {TWPacket} packet TradingView packet
|
|
32
37
|
* @returns {string} Websocket raw data
|
|
33
38
|
*/
|
|
@@ -40,6 +45,7 @@ module.exports = {
|
|
|
40
45
|
|
|
41
46
|
/**
|
|
42
47
|
* Parse compressed data
|
|
48
|
+
* @function parseCompressed
|
|
43
49
|
* @param {string} data Compressed data
|
|
44
50
|
* @returns {Promise<{}>} Parsed data
|
|
45
51
|
*/
|
package/src/quote/session.js
CHANGED
package/src/request.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const https = require('https');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {https.RequestOptions} options HTTPS Request options
|
|
5
|
+
* @param {boolean} [raw] Get raw or JSON data
|
|
6
|
+
* @param {string} [content] Request body content
|
|
7
|
+
* @returns {Promise<{ data: (string | object | array), cookies: string[] }>} Result
|
|
8
|
+
*/
|
|
9
|
+
function request(options = {}, raw = false, content = '') {
|
|
10
|
+
return new Promise((cb, err) => {
|
|
11
|
+
const req = https.request(options, (res) => {
|
|
12
|
+
let data = '';
|
|
13
|
+
res.on('data', (c) => { data += c; });
|
|
14
|
+
res.on('end', () => {
|
|
15
|
+
if (raw) {
|
|
16
|
+
cb({ data, cookies: res.headers['set-cookie'] });
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
data = JSON.parse(data);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.log(data);
|
|
24
|
+
err(new Error('Can\'t parse server response'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
cb({ data, cookies: res.headers['set-cookie'] });
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
req.on('error', err);
|
|
33
|
+
req.end(content);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = request;
|
package/src/types.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @typedef {string} MarketSymbol Market symbol (like: 'BTCEUR' or 'KRAKEN:BTCEUR')
|
|
3
|
-
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
4
6
|
* @typedef {'Etc/UTC' | 'exchange'
|
|
5
7
|
* | 'Pacific/Honolulu' | 'America/Juneau' | 'America/Los_Angeles'
|
|
6
8
|
* | 'America/Phoenix' | 'America/Vancouver' | 'US/Mountain'
|
|
@@ -23,7 +25,9 @@
|
|
|
23
25
|
* | 'Asia/Taipei' | 'Asia/Seoul' | 'Asia/Tokyo' | 'Australia/Brisbane'
|
|
24
26
|
* | 'Australia/Adelaide' | 'Australia/Sydney' | 'Pacific/Norfolk'
|
|
25
27
|
* | 'Pacific/Auckland' | 'Pacific/Fakaofo' | 'Pacific/Chatham'} Timezone (Chart) timezone
|
|
26
|
-
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
27
31
|
* @typedef {'1' | '3' | '5' | '15' | '30'
|
|
28
32
|
* | '45' | '60' | '120' | '180' | '240'
|
|
29
33
|
* | '1D' | '1W' | '1M' | 'D' | 'W' | 'M'} TimeFrame
|
package/src/utils.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
+
/**
|
|
3
|
+
* Generates a session id
|
|
4
|
+
* @function genSessionID
|
|
5
|
+
* @param {String} type Session type
|
|
6
|
+
* @returns {string}
|
|
7
|
+
*/
|
|
2
8
|
genSessionID(type = 'xs') {
|
|
3
9
|
let r = '';
|
|
4
10
|
const c = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|