@mathieuc/tradingview 3.4.0 → 3.4.2

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.
@@ -1,31 +1,18 @@
1
1
  const os = require('os');
2
- const https = require('https');
3
- const request = require('./request');
4
- const FormData = require('./FormData');
2
+ const axios = require('axios');
5
3
 
6
- const PinePermManager = require('./classes/PinePermManager');
7
4
  const PineIndicator = require('./classes/PineIndicator');
8
5
 
6
+ const validateStatus = (status) => status < 500;
7
+
9
8
  const indicators = ['Recommend.Other', 'Recommend.All', 'Recommend.MA'];
10
9
  const builtInIndicList = [];
11
10
 
12
11
  async function fetchScanData(tickers = [], type = '', columns = []) {
13
- let { data } = await request({
14
- method: 'POST',
15
- hostname: 'scanner.tradingview.com',
16
- path: `/${type}/scan`,
17
- headers: {
18
- 'Content-Type': 'application/json',
19
- },
20
- }, true, JSON.stringify({ symbols: { tickers }, columns }));
21
-
22
- if (!data.startsWith('{')) throw new Error('Wrong screener or symbol');
23
-
24
- try {
25
- data = JSON.parse(data);
26
- } catch (e) {
27
- throw new Error('Can\'t parse server response');
28
- }
12
+ const { data } = await axios.post(`https://scanner.tradingview.com/${type}/scan`, {
13
+ symbols: { tickers },
14
+ columns,
15
+ }, { validateStatus });
29
16
 
30
17
  return data;
31
18
  }
@@ -53,40 +40,40 @@ async function fetchScanData(tickers = [], type = '', columns = []) {
53
40
  * }} Periods
54
41
  */
55
42
 
56
- /**
57
- * @typedef {string | 'forex' | 'crypto'
58
- * | 'america' | 'australia' | 'canada' | 'egypt'
59
- * | 'germany' | 'india' | 'israel' | 'italy'
60
- * | 'luxembourg' | 'poland' | 'sweden' | 'turkey'
61
- * | 'uk' | 'vietnam'} Screener
62
- * You can use `getScreener(exchange)` function for non-forex and non-crypto markets.
63
- */
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
+ // */
64
51
 
65
52
  module.exports = {
66
- /**
67
- * Get a screener from an exchange
68
- * @function getScreener
69
- * @param {string} exchange Example: BINANCE, EURONEXT, NASDAQ
70
- * @returns {Screener}
71
- */
72
- getScreener(exchange) {
73
- const e = exchange.toUpperCase();
74
- if (['NASDAQ', 'NYSE', 'NYSE ARCA', 'OTC'].includes(e)) return 'america';
75
- if (['ASX'].includes(e)) return 'australia';
76
- if (['TSX', 'TSXV', 'CSE', 'NEO'].includes(e)) return 'canada';
77
- if (['EGX'].includes(e)) return 'egypt';
78
- if (['FWB', 'SWB', 'XETR'].includes(e)) return 'germany';
79
- if (['BSE', 'NSE'].includes(e)) return 'india';
80
- if (['TASE'].includes(e)) return 'israel';
81
- if (['MIL', 'MILSEDEX'].includes(e)) return 'italy';
82
- if (['LUXSE'].includes(e)) return 'luxembourg';
83
- if (['NEWCONNECT'].includes(e)) return 'poland';
84
- if (['NGM'].includes(e)) return 'sweden';
85
- if (['BIST'].includes(e)) return 'turkey';
86
- if (['LSE', 'LSIN'].includes(e)) return 'uk';
87
- if (['HNX'].includes(e)) return 'vietnam';
88
- return exchange.toLowerCase();
89
- },
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
+ // },
90
77
 
91
78
  /**
92
79
  * Get technical analysis
@@ -138,20 +125,25 @@ module.exports = {
138
125
  * @returns {Promise<SearchMarketResult[]>} Search results
139
126
  */
140
127
  async searchMarket(search, filter = '') {
141
- const { data } = await request({
142
- host: 'symbol-search.tradingview.com',
143
- path: `/symbol_search/?text=${search.replace(/ /g, '%20')}&type=${filter}`,
144
- origin: 'https://www.tradingview.com',
145
- });
128
+ const { data } = await axios.get(
129
+ `https://symbol-search.tradingview.com/symbol_search/?text=${search.replace(/ /g, '%20')}&type=${filter}`,
130
+ {
131
+ validateStatus,
132
+ headers: {
133
+ origin: 'https://www.tradingview.com',
134
+ },
135
+ },
136
+ );
146
137
 
147
138
  return data.map((s) => {
148
139
  const exchange = s.exchange.split(' ')[0];
149
140
  const id = `${exchange}:${s.symbol}`;
150
141
 
151
- const screener = (['forex', 'crypto'].includes(s.type)
152
- ? s.type
153
- : this.getScreener(exchange)
154
- );
142
+ // const screener = (['forex', 'crypto'].includes(s.type)
143
+ // ? s.type
144
+ // : this.getScreener(exchange)
145
+ // );
146
+ const screener = 'global';
155
147
 
156
148
  return {
157
149
  id,
@@ -189,17 +181,18 @@ module.exports = {
189
181
  async searchIndicator(search = '') {
190
182
  if (!builtInIndicList.length) {
191
183
  await Promise.all(['standard', 'candlestick', 'fundamental'].map(async (type) => {
192
- builtInIndicList.push(...(await request({
193
- host: 'pine-facade.tradingview.com',
194
- path: `/pine-facade/list/?filter=${type}`,
195
- })).data);
184
+ const { data } = await axios.get(
185
+ `https://pine-facade.tradingview.com/pine-facade/list/?filter=${type}`,
186
+ { validateStatus },
187
+ );
188
+ builtInIndicList.push(...data);
196
189
  }));
197
190
  }
198
191
 
199
- const { data } = await request({
200
- host: 'www.tradingview.com',
201
- path: `/pubscripts-suggest-json/?search=${search.replace(/ /g, '%20')}`,
202
- });
192
+ const { data } = await axios.get(
193
+ `https://www.tradingview.com/pubscripts-suggest-json/?search=${search.replace(/ /g, '%20')}`,
194
+ { validateStatus },
195
+ );
203
196
 
204
197
  function norm(str = '') {
205
198
  return str.toUpperCase().replace(/[^A-Z]/g, '');
@@ -255,16 +248,10 @@ module.exports = {
255
248
  async getIndicator(id, version = 'last') {
256
249
  const indicID = id.replace(/ |%/g, '%25');
257
250
 
258
- let { data } = await request({
259
- host: 'pine-facade.tradingview.com',
260
- path: `/pine-facade/translate/${indicID}/${version}`,
261
- }, true);
262
-
263
- try {
264
- data = JSON.parse(data);
265
- } catch (e) {
266
- throw new Error(`Inexistent or unsupported indicator: '${id}'`);
267
- }
251
+ const { data } = await axios.get(
252
+ `https://pine-facade.tradingview.com/pine-facade/translate/${indicID}/${version}`,
253
+ { validateStatus },
254
+ );
268
255
 
269
256
  if (!data.success || !data.result.metaInfo || !data.result.metaInfo.inputs) {
270
257
  throw new Error(`Inexistent or unsupported indicator: "${data.reason}"`);
@@ -342,6 +329,7 @@ module.exports = {
342
329
  * @prop {number} notifications.following Notification from following accounts
343
330
  * @prop {string} session User session
344
331
  * @prop {string} sessionHash User session hash
332
+ * @prop {string} signature User session signature
345
333
  * @prop {string} privateChannel User private channel
346
334
  * @prop {string} authToken User auth token
347
335
  * @prop {Date} joinDate Account creation date
@@ -357,26 +345,28 @@ module.exports = {
357
345
  * @returns {Promise<User>} Token
358
346
  */
359
347
  async loginUser(username, password, remember = true, UA = 'TWAPI/3.0') {
360
- const formData = new FormData();
361
- formData.append('username', username);
362
- formData.append('password', password);
363
- if (remember) formData.append('remember', 'on');
364
-
365
- const { data, cookies } = await request({
366
- method: 'POST',
367
- host: 'www.tradingview.com',
368
- path: '/accounts/signin/',
369
- headers: {
370
- referer: 'https://www.tradingview.com',
371
- 'Content-Type': `multipart/form-data; boundary=${formData.boundary}`,
372
- 'User-agent': `${UA} (${os.version()}; ${os.platform()}; ${os.arch()})`,
348
+ const { data, headers } = await axios.post(
349
+ 'https://www.tradingview.com/accounts/signin/',
350
+ `username=${username}&password=${password}${remember ? '&remember=on' : ''}`,
351
+ {
352
+ validateStatus,
353
+ headers: {
354
+ referer: 'https://www.tradingview.com',
355
+ 'Content-Type': 'application/x-www-form-urlencoded',
356
+ 'User-agent': `${UA} (${os.version()}; ${os.platform()}; ${os.arch()})`,
357
+ },
373
358
  },
374
- }, false, formData.toString());
359
+ );
360
+
361
+ const cookies = headers['set-cookie'];
375
362
 
376
363
  if (data.error) throw new Error(data.error);
377
364
 
378
- const cookie = cookies.find((c) => c.includes('sessionid='));
379
- const session = (cookie.match(/sessionid=(.*?);/) ?? [])[1];
365
+ const sessionCookie = cookies.find((c) => c.includes('sessionid='));
366
+ const session = (sessionCookie.match(/sessionid=(.*?);/) ?? [])[1];
367
+
368
+ const signCookie = cookies.find((c) => c.includes('sessionid_sign='));
369
+ const signature = (signCookie.match(/sessionid_sign=(.*?);/) ?? [])[1];
380
370
 
381
371
  return {
382
372
  id: data.user.id,
@@ -388,6 +378,7 @@ module.exports = {
388
378
  followers: data.user.followers,
389
379
  notifications: data.user.notification_count,
390
380
  session,
381
+ signature,
391
382
  sessionHash: data.user.session_hash,
392
383
  privateChannel: data.user.private_channel,
393
384
  authToken: data.user.auth_token,
@@ -399,93 +390,74 @@ module.exports = {
399
390
  * Get user from 'sessionid' cookie
400
391
  * @function getUser
401
392
  * @param {string} session User 'sessionid' cookie
393
+ * @param {string} [signature] User 'sessionid_sign' cookie
402
394
  * @param {string} [location] Auth page location (For france: https://fr.tradingview.com/)
403
395
  * @returns {Promise<User>} Token
404
396
  */
405
- async getUser(session, location = 'https://www.tradingview.com/') {
406
- return new Promise((cb, err) => {
407
- https.get(location, {
408
- headers: { cookie: `sessionid=${session}` },
409
- }, (res) => {
410
- let rs = '';
411
- res.on('data', (d) => { rs += d; });
412
- res.on('end', async () => {
413
- if (res.headers.location && location !== res.headers.location) {
414
- cb(await module.exports.getUser(session, res.headers.location));
415
- return;
416
- }
417
- if (rs.includes('auth_token')) {
418
- cb({
419
- id: /"id":([0-9]{1,10}),/.exec(rs)[1],
420
- username: /"username":"(.*?)"/.exec(rs)[1],
421
- firstName: /"first_name":"(.*?)"/.exec(rs)[1],
422
- lastName: /"last_name":"(.*?)"/.exec(rs)[1],
423
- reputation: parseFloat(/"reputation":(.*?),/.exec(rs)[1] || 0),
424
- following: parseFloat(/,"following":([0-9]*?),/.exec(rs)[1] || 0),
425
- followers: parseFloat(/,"followers":([0-9]*?),/.exec(rs)[1] || 0),
426
- notifications: {
427
- following: parseFloat(/"notification_count":\{"following":([0-9]*),/.exec(rs)[1] || 0),
428
- user: parseFloat(/"notification_count":\{"following":[0-9]*,"user":([0-9]*)/.exec(rs)[1] || 0),
429
- },
430
- session,
431
- sessionHash: /"session_hash":"(.*?)"/.exec(rs)[1],
432
- privateChannel: /"private_channel":"(.*?)"/.exec(rs)[1],
433
- authToken: /"auth_token":"(.*?)"/.exec(rs)[1],
434
- joinDate: new Date(/"date_joined":"(.*?)"/.exec(rs)[1] || 0),
435
- });
436
- } else err(new Error('Wrong or expired sessionid'));
437
- });
438
-
439
- res.on('error', err);
440
- }).end();
397
+ async getUser(session, signature = '', location = 'https://www.tradingview.com/') {
398
+ const { data } = await axios.get(location, {
399
+ validateStatus,
400
+ headers: {
401
+ cookie: `sessionid=${session}${signature ? `;sessionid_sign=${signature};` : ''}`,
402
+ },
441
403
  });
404
+
405
+ if (data.includes('auth_token')) {
406
+ return {
407
+ id: /"id":([0-9]{1,10}),/.exec(data)?.[1],
408
+ username: /"username":"(.*?)"/.exec(data)?.[1],
409
+ firstName: /"first_name":"(.*?)"/.exec(data)?.[1],
410
+ lastName: /"last_name":"(.*?)"/.exec(data)?.[1],
411
+ reputation: parseFloat(/"reputation":(.*?),/.exec(data)?.[1] || 0),
412
+ following: parseFloat(/,"following":([0-9]*?),/.exec(data)?.[1] || 0),
413
+ followers: parseFloat(/,"followers":([0-9]*?),/.exec(data)?.[1] || 0),
414
+ notifications: {
415
+ following: parseFloat(/"notification_count":\{"following":([0-9]*),/.exec(data)?.[1] || 0),
416
+ user: parseFloat(/"notification_count":\{"following":[0-9]*,"user":([0-9]*)/.exec(data)?.[1] || 0),
417
+ },
418
+ session,
419
+ signature,
420
+ sessionHash: /"session_hash":"(.*?)"/.exec(data)?.[1],
421
+ privateChannel: /"private_channel":"(.*?)"/.exec(data)?.[1],
422
+ authToken: /"auth_token":"(.*?)"/.exec(data)?.[1],
423
+ joinDate: new Date(/"date_joined":"(.*?)"/.exec(data)?.[1] || 0),
424
+ };
425
+ }
426
+
427
+ throw new Error('Wrong or expired sessionid/signature');
442
428
  },
443
429
 
444
430
  /**
445
431
  * Get user's private indicators from a 'sessionid' cookie
446
432
  * @function getPrivateIndicators
447
433
  * @param {string} session User 'sessionid' cookie
434
+ * @param {string} [signature] User 'sessionid_sign' cookie
448
435
  * @returns {Promise<SearchIndicatorResult[]>} Search results
449
436
  */
450
- async getPrivateIndicators(session) {
451
- return new Promise((cb, err) => {
452
- https.get('https://pine-facade.tradingview.com/pine-facade/list?filter=saved', {
453
- headers: { cookie: `sessionid=${session}` },
454
- }, (res) => {
455
- let rs = '';
456
- res.on('data', (d) => { rs += d; });
457
- res.on('end', async () => {
458
- try {
459
- rs = JSON.parse(rs);
460
- } catch (error) {
461
- err(new Error('Can\'t parse private indicator list'));
462
- return;
463
- }
464
-
465
- cb(rs.map((ind) => ({
466
- id: ind.scriptIdPart,
467
- version: ind.version,
468
- name: ind.scriptName,
469
- author: {
470
- id: -1,
471
- username: '@ME@',
472
- },
473
- image: ind.imageUrl,
474
- access: 'private',
475
- source: ind.scriptSource,
476
- type: (ind.extra && ind.extra.kind) ? ind.extra.kind : 'study',
477
- get() {
478
- return module.exports.getIndicator(ind.scriptIdPart, ind.version);
479
- },
480
- getManager() {
481
- return new PinePermManager(ind.scriptIdPart);
482
- },
483
- })));
484
- });
485
-
486
- res.on('error', err);
487
- }).end();
437
+ async getPrivateIndicators(session, signature = '') {
438
+ const { data } = await axios.get('https://pine-facade.tradingview.com/pine-facade/list?filter=saved', {
439
+ validateStatus,
440
+ headers: {
441
+ cookie: `sessionid=${session}${signature ? `;sessionid_sign=${signature};` : ''}`,
442
+ },
488
443
  });
444
+
445
+ return data.map((ind) => ({
446
+ id: ind.scriptIdPart,
447
+ version: ind.version,
448
+ name: ind.scriptName,
449
+ author: {
450
+ id: -1,
451
+ username: '@ME@',
452
+ },
453
+ image: ind.imageUrl,
454
+ access: 'private',
455
+ source: ind.scriptSource,
456
+ type: (ind.extra && ind.extra.kind) ? ind.extra.kind : 'study',
457
+ get() {
458
+ return module.exports.getIndicator(ind.scriptIdPart, ind.version);
459
+ },
460
+ }));
489
461
  },
490
462
 
491
463
  /**
@@ -493,25 +465,34 @@ module.exports = {
493
465
  * @typedef {Object} UserCredentials
494
466
  * @prop {number} id User ID
495
467
  * @prop {string} session User session ('sessionid' cookie)
468
+ * @prop {string} [signature] User session signature ('sessionid_sign' cookie)
496
469
  */
497
470
 
498
471
  /**
499
472
  * Get a chart token from a layout ID and the user credentials if the layout is not public
500
473
  * @function getChartToken
501
474
  * @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
502
- * @param {UserCredentials} [credentials] User credentials (id + session)
475
+ * @param {UserCredentials} [credentials] User credentials (id + session + [signature])
503
476
  * @returns {Promise<string>} Token
504
477
  */
505
478
  async getChartToken(layout, credentials = {}) {
506
- const creds = credentials.id && credentials.session;
507
- const userID = creds ? credentials.id : -1;
508
- const session = creds ? credentials.session : null;
509
-
510
- const { data } = await request({
511
- host: 'www.tradingview.com',
512
- path: `/chart-token/?image_url=${layout}&user_id=${userID}`,
513
- headers: { cookie: session ? `sessionid=${session}` : '' },
514
- });
479
+ const { id, session, signature } = (
480
+ credentials.id && credentials.session
481
+ ? credentials
482
+ : { id: -1, session: null, signature: null }
483
+ );
484
+
485
+ const { data } = await axios.get(
486
+ `https://www.tradingview.com/chart-token/?image_url=${layout}&user_id=${id}`,
487
+ {
488
+ validateStatus,
489
+ headers: {
490
+ cookie: session
491
+ ? `sessionid=${session}${signature ? `;sessionid_sign=${signature};` : ''}`
492
+ : '',
493
+ },
494
+ },
495
+ );
515
496
 
516
497
  if (!data.token) throw new Error('Wrong layout or credentials');
517
498
 
@@ -545,21 +526,25 @@ module.exports = {
545
526
  * @function getDrawings
546
527
  * @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
547
528
  * @param {string | ''} [symbol] Market filter (Like: 'BINANCE:BTCEUR')
548
- * @param {UserCredentials} [credentials] User credentials (id + session)
529
+ * @param {UserCredentials} [credentials] User credentials (id + session + [signature])
549
530
  * @param {number} [chartID] Chart ID
550
531
  * @returns {Promise<Drawing[]>} Drawings
551
532
  */
552
- async getDrawings(layout, symbol = '', credentials = {}, chartID = 1) {
533
+ async getDrawings(layout, symbol = '', credentials = {}, chartID = '_shared') {
553
534
  const chartToken = await module.exports.getChartToken(layout, credentials);
554
- const creds = credentials.id && credentials.session;
555
- const session = creds ? credentials.session : null;
556
-
557
- const { data } = await request({
558
- host: 'charts-storage.tradingview.com',
559
- path: `/charts-storage/layout/${layout}/sources?chart_id=${chartID
560
- }&jwt=${chartToken}${symbol ? `&symbol=${symbol}` : ''}`,
561
- headers: { cookie: session ? `sessionid=${session}` : '' },
562
- });
535
+
536
+ const { data } = await axios.get(
537
+ `https://charts-storage.tradingview.com/charts-storage/get/layout/${
538
+ layout
539
+ }/sources?chart_id=${
540
+ chartID
541
+ }&jwt=${
542
+ chartToken
543
+ }${
544
+ (symbol ? `&symbol=${symbol}` : '')
545
+ }`,
546
+ { validateStatus },
547
+ );
563
548
 
564
549
  if (!data.payload) throw new Error('Wrong layout, user credentials, or chart id.');
565
550
 
package/vite.config.js ADDED
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ test: {
3
+ testTimeout: 10000,
4
+ setupFiles: 'dotenv/config',
5
+ },
6
+ };
package/src/FormData.js DELETED
@@ -1,36 +0,0 @@
1
- /** @class */
2
- class FormData {
3
- #string = '';
4
-
5
- #boundary = '';
6
-
7
- get boundary() {
8
- return this.#boundary;
9
- }
10
-
11
- constructor() {
12
- const random = (Math.random() * 10 ** 20).toString(36);
13
- this.#boundary = `${random}`;
14
- this.#string = `--${this.boundary}`;
15
- }
16
-
17
- /**
18
- * Adds a property to the FormData object
19
- * @param {string} key Property key
20
- * @param {string} value Property value
21
- */
22
- append(key, value) {
23
- this.#string += `\r\nContent-Disposition: form-data; name="${key}"`;
24
- this.#string += `\r\n\r\n${value}`;
25
- this.#string += `\r\n--${this.boundary}`;
26
- }
27
-
28
- /**
29
- * @returns {string}
30
- */
31
- toString() {
32
- return `${this.#string}--`;
33
- }
34
- }
35
-
36
- module.exports = FormData;
package/src/request.js DELETED
@@ -1,37 +0,0 @@
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/test.js DELETED
@@ -1,70 +0,0 @@
1
- /* eslint-disable no-continue */
2
- /* eslint-disable no-await-in-loop */
3
- /* eslint-disable import/no-dynamic-require */
4
- /* eslint-disable no-restricted-syntax */
5
- /* eslint-disable global-require */
6
-
7
- const fs = require('fs');
8
- require('@mathieuc/console')(
9
- '§', // Character you want to use (defaut: '§')
10
- true, // Active timestamp (defaut: false)
11
- );
12
-
13
- const TESTS = {};
14
-
15
- function err(name) {
16
- return (...msg) => {
17
- TESTS[name].errors += 1;
18
- console.error('§30§101 > §0', ...msg);
19
- };
20
- }
21
-
22
- function warn(name) {
23
- return (...msg) => {
24
- TESTS[name].warnings += 1;
25
- console.warn('§30§103 > §0', ...msg);
26
- };
27
- }
28
-
29
- function log() {
30
- return (...msg) => console.log('§30§107 > §0', ...msg);
31
- }
32
-
33
- function success() {
34
- return (...msg) => console.info('§30§102 > §0', ...msg);
35
- }
36
-
37
- (async () => {
38
- console.info('§90§30§104 ==== Starting tests ==== §0');
39
-
40
- for (const file of fs.readdirSync('./tests').filter((f) => f.endsWith('.js'))) {
41
- if (process.argv[2] && !file.startsWith(process.argv[2])) continue;
42
- const test = require(`./tests/${file}`);
43
- const name = file.replace(/\.js/g, '');
44
- TESTS[name] = { errors: 0, warnings: 0 };
45
- console.log(`§90§30§107 ${name}`);
46
- await new Promise((cb) => test(log(), success(), warn(name), err(name), cb));
47
- }
48
-
49
- console.info('§90§30§104 ==== ALL TESTS DONE ==== §0\n');
50
-
51
- let errored = false;
52
-
53
- Object.keys(TESTS).forEach((t) => {
54
- let color = '2';
55
- if (TESTS[t].warnings) color = '3';
56
- if (TESTS[t].errors) {
57
- color = '1';
58
- errored = true;
59
- }
60
-
61
- console.info(`§90§30§10${color} ${t} §0 §91E§0: ${TESTS[t].errors}§0 §93W§0: ${TESTS[t].warnings}`);
62
- });
63
-
64
- process.exit(errored ? 1 : 0);
65
- })();
66
-
67
- setTimeout(() => {
68
- console.log('§30§101 TIMEOUT §0');
69
- throw new Error('Timeout');
70
- }, 60000);
@@ -1,17 +0,0 @@
1
- const TradingView = require('../main');
2
-
3
- module.exports = async (log, success, warn, err, cb) => {
4
- log('Searching market: \'BINANCE:\'');
5
- const markets = await TradingView.searchMarket('BINANCE:');
6
- success('Found', markets.length, 'markets');
7
-
8
- log('Searching indicator: \'RSI\'');
9
- const indicators = await TradingView.searchIndicator('RSI');
10
- success('Found', indicators.length, 'indicators');
11
-
12
- if (markets.length < 10 || indicators.length < 10) {
13
- err('Not enough results');
14
- }
15
-
16
- cb();
17
- };