@mathieuc/tradingview 3.2.0 → 3.3.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.
package/.eslintrc.js CHANGED
@@ -14,5 +14,11 @@ module.exports = {
14
14
  },
15
15
  rules: {
16
16
  'no-console': 'off',
17
+ 'import/no-extraneous-dependencies': [
18
+ 'error',
19
+ {
20
+ devDependencies: ['./test.js', './tests/**'],
21
+ },
22
+ ],
17
23
  },
18
24
  };
package/README.md CHANGED
@@ -1,14 +1,16 @@
1
- # TradingView API [![Open in Visual Studio Code](https://open.vscode.dev/badges/open-in-vscode.svg)](https://open.vscode.dev/Mathieu2301/TradingView-API) [![GitHub stars](https://img.shields.io/github/stars/Mathieu2301/TradingView-API.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/Mathieu2301/TradingView-API/stargazers/)
1
+ # TradingView API [![GitHub stars](https://img.shields.io/github/stars/Mathieu2301/TradingView-API.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/Mathieu2301/TradingView-API/stargazers/)
2
2
 
3
3
  [![Tests](https://github.com/Mathieu2301/TradingView-API/actions/workflows/node.js.yml/badge.svg)](https://github.com/Mathieu2301/TradingView-API/actions/workflows/node.js.yml)
4
- [![Minimum node.js version](https://badgen.net/npm/node/@mathieuc/tradingview)](https://npmjs.com/@mathieuc/tradingview)
5
- [![Npm package yearly downloads](https://badgen.net/npm/dt/@mathieuc/tradingview)](https://npmjs.com/@mathieuc/tradingview)
4
+ [![CodeFactor](https://www.codefactor.io/repository/github/mathieu2301/tradingview-api/badge/main)](https://www.codefactor.io/repository/github/mathieu2301/tradingview-api/overview/main)
6
5
  [![GitHub latest commit](https://img.shields.io/github/last-commit/Mathieu2301/TradingView-API)](https://GitHub.com/Mathieu2301/TradingView-API/commit/)
6
+ [![Npm package yearly downloads](https://badgen.net/npm/dt/@mathieuc/tradingview)](https://npmjs.com/@mathieuc/tradingview)
7
+ [![Minimum node.js version](https://badgen.net/npm/node/@mathieuc/tradingview)](https://npmjs.com/@mathieuc/tradingview)
7
8
  [![Npm package version](https://badgen.net/npm/v/@mathieuc/tradingview)](https://npmjs.com/package/@mathieuc/tradingview)
8
9
 
9
10
  Get realtime market prices and indicator values from Tradingview !
10
11
 
11
12
  ## Features
13
+
12
14
  - [x] Premium features
13
15
  - [x] Automatically backtest many strategies and try many settings in a very little time
14
16
  - [x] Get drawings you made on your chart
@@ -26,6 +28,7 @@ Get realtime market prices and indicator values from Tradingview !
26
28
  - IF YOU WANT A FEATURE, ASK ME !
27
29
 
28
30
  ## Possibilities
31
+
29
32
  - Trading bot
30
33
  - Discord alerts
31
34
  - Hard backtest
@@ -33,21 +36,31 @@ Get realtime market prices and indicator values from Tradingview !
33
36
  - Free replay mode for all timeframes
34
37
 
35
38
  ___
39
+
36
40
  ## Installation
37
41
 
38
42
  Stable version:
43
+
39
44
  ```ruby
40
45
  npm i @mathieuc/tradingview
41
46
  ```
47
+
42
48
  Last version:
49
+
43
50
  ```ruby
44
51
  npm i github:Mathieu2301/TradingView-API
45
52
  ```
46
53
 
47
54
  ## Examples
55
+
48
56
  You can find all the examples and snippets in `./examples` folder.
49
57
 
58
+ ## Before opening an issue
59
+
60
+ Please look at examples and previously resolved issues before opening a new one. I can't help everyone (especially for questions that are not library related but JavaScript related). Thank you for your understanding.
50
61
  ___
62
+
51
63
  ## Problems
64
+
52
65
  If you have errors in console or unwanted behavior,
53
66
  please create an issue [here](https://github.com/Mathieu2301/Tradingview-API/issues).
package/docs/DOCS.md ADDED
@@ -0,0 +1,3 @@
1
+ # Documentation
2
+
3
+ ### All the project is now JSDoc-ed :)
@@ -7,7 +7,7 @@ const TradingView = require('../main');
7
7
 
8
8
  const volumeProfile = new TradingView.BuiltInIndicator('VbPFixed@tv-basicstudies-139!');
9
9
 
10
- if (!process.argv[2] && volumeProfile.type !== 'VbPFixed@tv-basicstudies-139!') {
10
+ if (!process.argv[2] && !['VbPFixed@tv-basicstudies-139!', 'Volume@tv-basicstudies-144'].includes(volumeProfile.type)) {
11
11
  throw Error('Please specify your \'sessionid\' cookie');
12
12
  }
13
13
 
@@ -0,0 +1,26 @@
1
+ const TradingView = require('../main');
2
+
3
+ /*
4
+ This example tests the
5
+ getDrawings function
6
+ */
7
+
8
+ // First parameter must be the layoutID
9
+ // (if the layout is private) Second parameter must be the sessionid cookie
10
+ // (if the layout is private) Third parameter must be the userid (you can use getUser function)
11
+
12
+ if (!process.argv[2]) throw Error('Please specify a layoutID');
13
+
14
+ TradingView.getDrawings(process.argv[2], null, {
15
+ session: process.argv[3],
16
+ id: process.argv[4],
17
+ }).then((drawings) => {
18
+ console.log(`Found ${drawings.length} drawings:`, drawings.map((d) => ({
19
+ id: d.id,
20
+ symbol: d.symbol,
21
+ type: d.type,
22
+ text: d.state.text,
23
+ })));
24
+ }).catch((err) => {
25
+ console.error('Error:', err.message);
26
+ });
@@ -0,0 +1,16 @@
1
+ const TradingView = require('../main');
2
+
3
+ /*
4
+ This example tests the
5
+ user login function
6
+ */
7
+
8
+ if (!process.argv[2]) throw Error('Please specify your username/email');
9
+ if (!process.argv[3]) throw Error('Please specify your password');
10
+
11
+ TradingView.loginUser(process.argv[2], process.argv[3], false).then((user) => {
12
+ console.log('User:', user);
13
+ console.log('Sessionid:', user.session);
14
+ }).catch((err) => {
15
+ console.error('Login error:', err.message);
16
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mathieuc/tradingview",
3
- "version": "3.2.0",
3
+ "version": "3.3.2",
4
4
  "description": "Tradingview instant stocks API, indicator alerts, trading bot, and more !",
5
5
  "main": "main.js",
6
6
  "scripts": {
@@ -34,7 +34,6 @@
34
34
  "@mathieuc/console": "^1.0.1",
35
35
  "eslint": "^7.25.0",
36
36
  "eslint-config-airbnb-base": "^14.2.1",
37
- "eslint-plugin-import": "^2.22.1",
38
- "jsdoc-to-markdown": "^7.1.0"
37
+ "eslint-plugin-import": "^2.22.1"
39
38
  }
40
39
  }
package/src/FormData.js CHANGED
@@ -1,3 +1,4 @@
1
+ /** @class */
1
2
  class FormData {
2
3
  #string = '';
3
4
 
@@ -64,7 +64,9 @@ const ChartTypes = {
64
64
  * @prop {string} session Session (ex: '24x7')
65
65
  * @prop {string} session-correction Session correction
66
66
  * @prop {string} session-display Session display (ex: '24x7')
67
- *
67
+ */
68
+
69
+ /**
68
70
  * @typedef {Object} MarketInfos
69
71
  * @prop {string} series_id Used series (ex: 'ser_1')
70
72
  * @prop {string} base_currency Base currency (ex: 'BTC')
@@ -120,7 +122,7 @@ module.exports = (client) => class ChartSession {
120
122
  #replayMode = false;
121
123
 
122
124
  /** @type {Object<string, (): any>} */
123
- #replayOKCB = {}
125
+ #replayOKCB = {};
124
126
 
125
127
  /** Parent client */
126
128
  #client = client;
@@ -16,11 +16,11 @@ function getInputs(options) {
16
16
  if (options.pineId) pineInputs.pineId = options.pineId;
17
17
  if (options.pineVersion) pineInputs.pineVersion = options.pineVersion;
18
18
 
19
- Object.keys(options.inputs).forEach((inputID) => {
19
+ Object.keys(options.inputs).forEach((inputID, n) => {
20
20
  const input = options.inputs[inputID];
21
21
 
22
22
  pineInputs[inputID] = {
23
- v: input.value,
23
+ v: (input.type !== 'color') ? input.value : n,
24
24
  f: input.isFake,
25
25
  t: input.type,
26
26
  };
@@ -35,80 +35,80 @@ function getInputs(options) {
35
35
  /**
36
36
  * @typedef {Object} TradeReport Trade report
37
37
 
38
- * @property {Object} entry Trade entry
39
- * @property {string} entry.name Trade name
40
- * @property {'long' | 'short'} entry.type Entry type (long/short)
41
- * @property {number} entry.value Entry price value
42
- * @property {number} entry.time Entry timestamp
43
-
44
- * @property {Object} exit Trade exit
45
- * @property {'' | string} exit.name Trade name ('' if false exit)
46
- * @property {number} exit.value Exit price value
47
- * @property {number} exit.time Exit timestamp
48
-
49
- * @property {number} quantity Trade quantity
50
- * @property {RelAbsValue} profit Trade profit
51
- * @property {RelAbsValue} cumulative Trade cummulative profit
52
- * @property {RelAbsValue} runup Trade run-up
53
- * @property {RelAbsValue} drawdown Trade drawdown
38
+ * @prop {Object} entry Trade entry
39
+ * @prop {string} entry.name Trade name
40
+ * @prop {'long' | 'short'} entry.type Entry type (long/short)
41
+ * @prop {number} entry.value Entry price value
42
+ * @prop {number} entry.time Entry timestamp
43
+
44
+ * @prop {Object} exit Trade exit
45
+ * @prop {'' | string} exit.name Trade name ('' if false exit)
46
+ * @prop {number} exit.value Exit price value
47
+ * @prop {number} exit.time Exit timestamp
48
+
49
+ * @prop {number} quantity Trade quantity
50
+ * @prop {RelAbsValue} profit Trade profit
51
+ * @prop {RelAbsValue} cumulative Trade cummulative profit
52
+ * @prop {RelAbsValue} runup Trade run-up
53
+ * @prop {RelAbsValue} drawdown Trade drawdown
54
54
  */
55
55
 
56
56
  /**
57
57
  * @typedef {Object} PerfReport
58
- * @property {number} avgBarsInTrade Average bars in trade
59
- * @property {number} avgBarsInWinTrade Average bars in winning trade
60
- * @property {number} avgBarsInLossTrade Average bars in losing trade
61
- * @property {number} avgTrade Average trade gain
62
- * @property {number} avgTradePercent Average trade performace
63
- * @property {number} avgLosTrade Average losing trade gain
64
- * @property {number} avgLosTradePercent Average losing trade performace
65
- * @property {number} avgWinTrade Average winning trade gain
66
- * @property {number} avgWinTradePercent Average winning trade performace
67
- * @property {number} commissionPaid Commission paid
68
- * @property {number} grossLoss Gross loss value
69
- * @property {number} grossLossPercent Gross loss percent
70
- * @property {number} grossProfit Gross profit
71
- * @property {number} grossProfitPercent Gross profit percent
72
- * @property {number} largestLosTrade Largest losing trade gain
73
- * @property {number} largestLosTradePercent Largent losing trade performance (percentage)
74
- * @property {number} largestWinTrade Largest winning trade gain
75
- * @property {number} largestWinTradePercent Largest winning trade performance (percentage)
76
- * @property {number} marginCalls Margin calls
77
- * @property {number} maxContractsHeld Max Contracts Held
78
- * @property {number} netProfit Net profit
79
- * @property {number} netProfitPercent Net performance (percentage)
80
- * @property {number} numberOfLosingTrades Number of losing trades
81
- * @property {number} numberOfWiningTrades Number of winning trades
82
- * @property {number} percentProfitable Strategy winrate
83
- * @property {number} profitFactor Profit factor
84
- * @property {number} ratioAvgWinAvgLoss Ratio Average Win / Average Loss
85
- * @property {number} totalOpenTrades Total open trades
86
- * @property {number} totalTrades Total trades
58
+ * @prop {number} avgBarsInTrade Average bars in trade
59
+ * @prop {number} avgBarsInWinTrade Average bars in winning trade
60
+ * @prop {number} avgBarsInLossTrade Average bars in losing trade
61
+ * @prop {number} avgTrade Average trade gain
62
+ * @prop {number} avgTradePercent Average trade performace
63
+ * @prop {number} avgLosTrade Average losing trade gain
64
+ * @prop {number} avgLosTradePercent Average losing trade performace
65
+ * @prop {number} avgWinTrade Average winning trade gain
66
+ * @prop {number} avgWinTradePercent Average winning trade performace
67
+ * @prop {number} commissionPaid Commission paid
68
+ * @prop {number} grossLoss Gross loss value
69
+ * @prop {number} grossLossPercent Gross loss percent
70
+ * @prop {number} grossProfit Gross profit
71
+ * @prop {number} grossProfitPercent Gross profit percent
72
+ * @prop {number} largestLosTrade Largest losing trade gain
73
+ * @prop {number} largestLosTradePercent Largent losing trade performance (percentage)
74
+ * @prop {number} largestWinTrade Largest winning trade gain
75
+ * @prop {number} largestWinTradePercent Largest winning trade performance (percentage)
76
+ * @prop {number} marginCalls Margin calls
77
+ * @prop {number} maxContractsHeld Max Contracts Held
78
+ * @prop {number} netProfit Net profit
79
+ * @prop {number} netProfitPercent Net performance (percentage)
80
+ * @prop {number} numberOfLosingTrades Number of losing trades
81
+ * @prop {number} numberOfWiningTrades Number of winning trades
82
+ * @prop {number} percentProfitable Strategy winrate
83
+ * @prop {number} profitFactor Profit factor
84
+ * @prop {number} ratioAvgWinAvgLoss Ratio Average Win / Average Loss
85
+ * @prop {number} totalOpenTrades Total open trades
86
+ * @prop {number} totalTrades Total trades
87
87
  */
88
88
 
89
89
  /**
90
90
  * @typedef {Object} StrategyReport
91
- * @property {'EUR' | 'USD' | 'JPY' | '' | 'CHF'} [currency] Selected currency
92
- * @property {TradeReport[]} trades Trade list starting by the last
93
- * @property {Object} history History Chart value
94
- * @property {number[]} [history.buyHold] Buy hold values
95
- * @property {number[]} [history.buyHoldPercent] Buy hold percent values
96
- * @property {number[]} [history.drawDown] Drawdown values
97
- * @property {number[]} [history.drawDownPercent] Drawdown percent values
98
- * @property {number[]} [history.equity] Equity values
99
- * @property {number[]} [history.equityPercent] Equity percent values
100
- * @property {Object} performance Strategy performance
101
- * @property {PerfReport} [performance.all] Strategy long/short performances
102
- * @property {PerfReport} [performance.long] Strategy long performances
103
- * @property {PerfReport} [performance.short] Strategy short performances
104
- * @property {number} [performance.buyHoldReturn] Strategy Buy & Hold Return
105
- * @property {number} [performance.buyHoldReturnPercent] Strategy Buy & Hold Return percent
106
- * @property {number} [performance.maxDrawDown] Strategy max drawdown
107
- * @property {number} [performance.maxDrawDownPercent] Strategy max drawdown percent
108
- * @property {number} [performance.openPL] Strategy Open P&L (Profit And Loss)
109
- * @property {number} [performance.openPLPercent] Strategy Open P&L (Profit And Loss) percent
110
- * @property {number} [performance.sharpeRatio] Strategy Sharpe Ratio
111
- * @property {number} [performance.sortinoRatio] Strategy Sortino Ratio
91
+ * @prop {'EUR' | 'USD' | 'JPY' | '' | 'CHF'} [currency] Selected currency
92
+ * @prop {TradeReport[]} trades Trade list starting by the last
93
+ * @prop {Object} history History Chart value
94
+ * @prop {number[]} [history.buyHold] Buy hold values
95
+ * @prop {number[]} [history.buyHoldPercent] Buy hold percent values
96
+ * @prop {number[]} [history.drawDown] Drawdown values
97
+ * @prop {number[]} [history.drawDownPercent] Drawdown percent values
98
+ * @prop {number[]} [history.equity] Equity values
99
+ * @prop {number[]} [history.equityPercent] Equity percent values
100
+ * @prop {Object} performance Strategy performance
101
+ * @prop {PerfReport} [performance.all] Strategy long/short performances
102
+ * @prop {PerfReport} [performance.long] Strategy long performances
103
+ * @prop {PerfReport} [performance.short] Strategy short performances
104
+ * @prop {number} [performance.buyHoldReturn] Strategy Buy & Hold Return
105
+ * @prop {number} [performance.buyHoldReturnPercent] Strategy Buy & Hold Return percent
106
+ * @prop {number} [performance.maxDrawDown] Strategy max drawdown
107
+ * @prop {number} [performance.maxDrawDownPercent] Strategy max drawdown percent
108
+ * @prop {number} [performance.openPL] Strategy Open P&L (Profit And Loss)
109
+ * @prop {number} [performance.openPLPercent] Strategy Open P&L (Profit And Loss) percent
110
+ * @prop {number} [performance.sharpeRatio] Strategy Sharpe Ratio
111
+ * @prop {number} [performance.sortinoRatio] Strategy Sortino Ratio
112
112
  */
113
113
 
114
114
  /**
@@ -280,6 +280,16 @@ module.exports = (chartSession) => class ChartStudy {
280
280
  changes.push('perfReport');
281
281
  }
282
282
 
283
+ if (parsed.data && parsed.data.report && parsed.data.report.trades) {
284
+ this.#strategyReport.trades = parsed.data.report.trades;
285
+ changes.push('tradesReport');
286
+ }
287
+
288
+ if (parsed.data && parsed.data.report && parsed.data.report.history) {
289
+ this.#strategyReport.history = parsed.data.report.history;
290
+ changes.push('historyReport');
291
+ }
292
+
283
293
  if (parsed.dataCompressed) {
284
294
  const parsedC = await parseCompressed(parsed.dataCompressed);
285
295
 
@@ -372,7 +382,11 @@ module.exports = (chartSession) => class ChartStudy {
372
382
  this.#callbacks.studyCompleted.push(cb);
373
383
  }
374
384
 
375
- /** @typedef {'plots' | 'perfReport' | 'fullReport'} UpdateChangeType */
385
+ /**
386
+ * @typedef {
387
+ * 'plots' | 'perfReport' | 'tradesReport' | 'historyReport' | 'fullReport'
388
+ * } UpdateChangeType
389
+ */
376
390
 
377
391
  /**
378
392
  * When an indicator update happens
@@ -68,6 +68,7 @@ const defaultValues = {
68
68
  },
69
69
  };
70
70
 
71
+ /** @class */
71
72
  module.exports = class BuiltInIndicator {
72
73
  /** @type {BuiltInIndicatorType} */
73
74
  #type;
@@ -4,7 +4,9 @@
4
4
  * @property {string} inline Input inline name
5
5
  * @property {string} [internalID] Input internal ID
6
6
  * @property {string} [tooltip] Input tooltip
7
- * @property {'text' | 'source' | 'integer' | 'float' | 'resolution' | 'bool'} type Input type
7
+ * @property {'text' | 'source' | 'integer'
8
+ * | 'float' | 'resolution' | 'bool' | 'color'
9
+ * } type Input type
8
10
  * @property {string | number | boolean} value Input default value
9
11
  * @property {boolean} isHidden If the input is hidden
10
12
  * @property {boolean} isFake If the input is fake
@@ -26,6 +28,8 @@
26
28
  * @typedef {'Script@tv-scripting-101!'
27
29
  * | 'StrategyScript@tv-scripting-101!'} IndicatorType Indicator type
28
30
  */
31
+
32
+ /** @class */
29
33
  module.exports = class PineIndicator {
30
34
  #options;
31
35
 
@@ -113,12 +117,8 @@ module.exports = class PineIndicator {
113
117
  text: 'String',
114
118
  };
115
119
 
116
- if (
117
- (input.type === 'bool' && typeof value !== 'boolean')
118
- || (input.type === 'integer' && typeof value !== 'number')
119
- || (input.type === 'float' && typeof value !== 'number')
120
- || (input.type === 'text' && typeof value !== 'string')
121
- ) {
120
+ // eslint-disable-next-line valid-typeof
121
+ if (types[input.type] && typeof value !== types[input.type].toLowerCase()) {
122
122
  throw new Error(`Input '${input.name}' (${propI}) must be a ${types[input.type]} !`);
123
123
  }
124
124
 
@@ -10,6 +10,7 @@ const FormData = require('../FormData');
10
10
  * @prop {string} created Authorization creation date
11
11
  */
12
12
 
13
+ /** @class */
13
14
  class PinePermManager {
14
15
  sessionId;
15
16
 
@@ -39,7 +40,7 @@ class PinePermManager {
39
40
  * @returns {AuthorizationUser[]}
40
41
  */
41
42
  async getUsers(limit = 10, order = '-created') {
42
- const data = await request({
43
+ const { data } = await request({
43
44
  method: 'POST',
44
45
  host: 'www.tradingview.com',
45
46
  path: `/pine_perm/list_users/?limit=${limit}&order_by=${order}`,
@@ -69,7 +70,7 @@ class PinePermManager {
69
70
  formData.append('expiration', expiration.toString());
70
71
  }
71
72
 
72
- const data = await request({
73
+ const { data } = await request({
73
74
  method: 'POST',
74
75
  host: 'www.tradingview.com',
75
76
  path: '/pine_perm/add/',
@@ -98,7 +99,7 @@ class PinePermManager {
98
99
  formData.append('expiration', expiration.toISOString());
99
100
  }
100
101
 
101
- const data = await request({
102
+ const { data } = await request({
102
103
  method: 'POST',
103
104
  host: 'www.tradingview.com',
104
105
  path: '/pine_perm/modify_user_expiration/',
@@ -123,7 +124,7 @@ class PinePermManager {
123
124
  formData.append('pine_id', this.pineId);
124
125
  formData.append('username_recip', username);
125
126
 
126
- const data = await request({
127
+ const { data } = await request({
127
128
  method: 'POST',
128
129
  host: 'www.tradingview.com',
129
130
  path: '/pine_perm/remove/',
package/src/client.js CHANGED
@@ -15,9 +15,10 @@ const chartSessionGenerator = require('./chart/session');
15
15
  /** @typedef {Object<string, Session>} SessionList Session list */
16
16
 
17
17
  /**
18
- * @typedef {(t: string, p: []) => null} SendPacket Send a custom packet
18
+ * @callback SendPacket Send a custom packet
19
19
  * @param {string} t Packet type
20
20
  * @param {string[]} p Packet data
21
+ * @returns {void}
21
22
  */
22
23
 
23
24
  /**
@@ -33,6 +34,7 @@ const chartSessionGenerator = require('./chart/session');
33
34
  * } ClientEvent
34
35
  */
35
36
 
37
+ /** @class */
36
38
  module.exports = class Client {
37
39
  #ws;
38
40
 
@@ -79,7 +81,7 @@ module.exports = class Client {
79
81
  /**
80
82
  * When client is connected
81
83
  * @param {() => void} cb Callback
82
- * @event
84
+ * @event onConnected
83
85
  */
84
86
  onConnected(cb) {
85
87
  this.#callbacks.connected.push(cb);
@@ -88,7 +90,7 @@ module.exports = class Client {
88
90
  /**
89
91
  * When client is disconnected
90
92
  * @param {() => void} cb Callback
91
- * @event
93
+ * @event onDisconnected
92
94
  */
93
95
  onDisconnected(cb) {
94
96
  this.#callbacks.disconnected.push(cb);
@@ -105,10 +107,12 @@ module.exports = class Client {
105
107
  * @prop {string} javastudies Javastudies
106
108
  * @prop {number} auth_scheme_vsn Auth scheme type
107
109
  * @prop {string} via Socket IP
110
+ */
108
111
 
112
+ /**
109
113
  * When client is logged
110
114
  * @param {(SocketSession: SocketSession) => void} cb Callback
111
- * @event
115
+ * @event onLogged
112
116
  */
113
117
  onLogged(cb) {
114
118
  this.#callbacks.logged.push(cb);
@@ -117,7 +121,7 @@ module.exports = class Client {
117
121
  /**
118
122
  * When server is pinging the client
119
123
  * @param {(i: number) => void} cb Callback
120
- * @event
124
+ * @event onPing
121
125
  */
122
126
  onPing(cb) {
123
127
  this.#callbacks.ping.push(cb);
@@ -126,7 +130,7 @@ module.exports = class Client {
126
130
  /**
127
131
  * When unparsed data is received
128
132
  * @param {(...{}) => void} cb Callback
129
- * @event
133
+ * @event onData
130
134
  */
131
135
  onData(cb) {
132
136
  this.#callbacks.data.push(cb);
@@ -135,7 +139,7 @@ module.exports = class Client {
135
139
  /**
136
140
  * When a client error happens
137
141
  * @param {(...{}) => void} cb Callback
138
- * @event
142
+ * @event onError
139
143
  */
140
144
  onError(cb) {
141
145
  this.#callbacks.error.push(cb);
@@ -144,7 +148,7 @@ module.exports = class Client {
144
148
  /**
145
149
  * When a client event happens
146
150
  * @param {(...{}) => void} cb Callback
147
- * @event
151
+ * @event onEvent
148
152
  */
149
153
  onEvent(cb) {
150
154
  this.#callbacks.event.push(cb);
@@ -203,6 +207,7 @@ module.exports = class Client {
203
207
  while (this.isOpen && this.#logged && this.#sendQueue.length > 0) {
204
208
  const packet = this.#sendQueue.shift();
205
209
  this.#ws.send(packet);
210
+ if (global.TW_DEBUG) console.log('§90§30§107 > §0', packet);
206
211
  }
207
212
  }
208
213
 
@@ -210,6 +215,7 @@ module.exports = class Client {
210
215
  * @typedef {Object} ClientOptions
211
216
  * @prop {string} [token] User auth token (in 'sessionid' cookie)
212
217
  * @prop {boolean} [DEBUG] Enable debug mode
218
+ * @prop {'data' | 'prodata' | 'widgetdata'} [server] Server type
213
219
  */
214
220
 
215
221
  /** Client object
@@ -218,7 +224,8 @@ module.exports = class Client {
218
224
  constructor(clientOptions = {}) {
219
225
  if (clientOptions.DEBUG) global.TW_DEBUG = clientOptions.DEBUG;
220
226
 
221
- this.#ws = new WebSocket('wss://widgetdata.tradingview.com/socket.io/websocket', {
227
+ const server = clientOptions.server || 'data';
228
+ this.#ws = new WebSocket(`wss://${server}.tradingview.com/socket.io/websocket`, {
222
229
  origin: 'https://s.tradingview.com',
223
230
  });
224
231
 
@@ -1,5 +1,7 @@
1
+ const os = require('os');
1
2
  const https = require('https');
2
3
  const request = require('./request');
4
+ const FormData = require('./FormData');
3
5
 
4
6
  const PinePermManager = require('./classes/PinePermManager');
5
7
  const PineIndicator = require('./classes/PineIndicator');
@@ -8,7 +10,7 @@ const indicators = ['Recommend.Other', 'Recommend.All', 'Recommend.MA'];
8
10
  const builtInIndicList = [];
9
11
 
10
12
  async function fetchScanData(tickers = [], type = '', columns = []) {
11
- let data = await request({
13
+ let { data } = await request({
12
14
  method: 'POST',
13
15
  hostname: 'scanner.tradingview.com',
14
16
  path: `/${type}/scan`,
@@ -28,11 +30,17 @@ async function fetchScanData(tickers = [], type = '', columns = []) {
28
30
  return data;
29
31
  }
30
32
 
33
+ /** @typedef {number} advice */
34
+
35
+ /**
36
+ * @typedef {{
37
+ * Other: advice,
38
+ * All: advice,
39
+ * MA: advice
40
+ * }} Period
41
+ */
42
+
31
43
  /**
32
- * @typedef {number} advice
33
- *
34
- * @typedef {{ Other: advice, All: advice, MA: advice }} Period
35
- *
36
44
  * @typedef {{
37
45
  * '1': Period,
38
46
  * '5': Period,
@@ -41,21 +49,25 @@ async function fetchScanData(tickers = [], type = '', columns = []) {
41
49
  * '240': Period,
42
50
  * '1D': Period,
43
51
  * '1W': Period,
44
- * '1M': Period,
52
+ * '1M': Period
45
53
  * }} Periods
46
- *
54
+ */
55
+
56
+ /**
47
57
  * @typedef {string | 'forex' | 'crypto'
48
58
  * | 'america' | 'australia' | 'canada' | 'egypt'
49
59
  * | 'germany' | 'india' | 'israel' | 'italy'
50
60
  * | 'luxembourg' | 'poland' | 'sweden' | 'turkey'
51
- * | 'uk' | 'vietnam'} screener
61
+ * | 'uk' | 'vietnam'} Screener
52
62
  * You can use `getScreener(exchange)` function for non-forex and non-crypto markets.
53
63
  */
54
64
 
55
65
  module.exports = {
56
66
  /**
67
+ * Get a screener from an exchange
68
+ * @function getScreener
57
69
  * @param {string} exchange Example: BINANCE, EURONEXT, NASDAQ
58
- * @returns {screener}
70
+ * @returns {Screener}
59
71
  */
60
72
  getScreener(exchange) {
61
73
  const e = exchange.toUpperCase();
@@ -78,7 +90,8 @@ module.exports = {
78
90
 
79
91
  /**
80
92
  * Get technical analysis
81
- * @param {screener} screener
93
+ * @function getTA
94
+ * @param {Screener} screener Market screener
82
95
  * @param {string} id Full market id (Example: COINBASE:BTCEUR)
83
96
  * @returns {Promise<Periods>} results
84
97
  */
@@ -104,24 +117,28 @@ module.exports = {
104
117
 
105
118
  /**
106
119
  * @typedef {Object} SearchMarketResult
107
- * @property {string} id
108
- * @property {string} exchange
109
- * @property {string} fullExchange
110
- * @property {string} screener
111
- * @property {string} symbol
112
- * @property {string} description
113
- * @property {string} type
114
- * @property {() => Promise<Periods>} getTA
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
115
128
  */
116
129
 
117
130
  /**
118
131
  * Find a symbol
132
+ * @function searchMarket
119
133
  * @param {string} search Keywords
120
- * @param {'stock' | 'futures' | 'forex' | 'cfd' | 'crypto' | 'index' | 'economic'} [filter]
134
+ * @param {'stock'
135
+ * | 'futures' | 'forex' | 'cfd'
136
+ * | 'crypto' | 'index' | 'economic'
137
+ * } [filter] Caterogy filter
121
138
  * @returns {Promise<SearchMarketResult[]>} Search results
122
139
  */
123
140
  async searchMarket(search, filter = '') {
124
- const data = await request({
141
+ const { data } = await request({
125
142
  host: 'symbol-search.tradingview.com',
126
143
  path: `/symbol_search/?text=${search.replace(/ /g, '%20')}&type=${filter}`,
127
144
  origin: 'https://www.tradingview.com',
@@ -151,34 +168,35 @@ module.exports = {
151
168
 
152
169
  /**
153
170
  * @typedef {Object} SearchIndicatorResult
154
- * @property {string} id Script ID
155
- * @property {string} version Script version
156
- * @property {string} name Script complete name
157
- * @property {{ id: number, username: string }} author Author user ID
158
- * @property {string} image Image ID https://tradingview.com/i/${image}
159
- * @property {string | ''} source Script source (if available)
160
- * @property {'study' | 'strategy'} type Script type (study / strategy)
161
- * @property {'open_source' | 'closed_source' | 'invite_only'
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'
162
179
  * | 'private' | 'other'} access Script access type
163
- * @property {() => Promise<PineIndicator>} get Get the full indicator informations
180
+ * @prop {() => Promise<PineIndicator>} get Get the full indicator informations
164
181
  */
165
182
 
166
183
  /**
167
184
  * Find an indicator
185
+ * @function searchIndicator
168
186
  * @param {string} search Keywords
169
187
  * @returns {Promise<SearchIndicatorResult[]>} Search results
170
188
  */
171
189
  async searchIndicator(search = '') {
172
190
  if (!builtInIndicList.length) {
173
191
  await Promise.all(['standard', 'candlestick', 'fundamental'].map(async (type) => {
174
- builtInIndicList.push(...await request({
192
+ builtInIndicList.push(...(await request({
175
193
  host: 'pine-facade.tradingview.com',
176
194
  path: `/pine-facade/list/?filter=${type}`,
177
- }));
195
+ })).data);
178
196
  }));
179
197
  }
180
198
 
181
- const data = await request({
199
+ const { data } = await request({
182
200
  host: 'www.tradingview.com',
183
201
  path: `/pubscripts-suggest-json/?search=${search.replace(/ /g, '%20')}`,
184
202
  });
@@ -229,6 +247,7 @@ module.exports = {
229
247
 
230
248
  /**
231
249
  * Get an indicator
250
+ * @function getIndicator
232
251
  * @param {string} id Indicator ID (Like: PUB;XXXXXXXXXXXXXXXXXXXXX)
233
252
  * @param {'last' | string} [version] Wanted version of the indicator
234
253
  * @returns {Promise<PineIndicator>} Indicator
@@ -236,7 +255,7 @@ module.exports = {
236
255
  async getIndicator(id, version = 'last') {
237
256
  const indicID = id.replace(/ |%/g, '%25');
238
257
 
239
- let data = await request({
258
+ let { data } = await request({
240
259
  host: 'pine-facade.tradingview.com',
241
260
  path: `/pine-facade/translate/${indicID}/${version}`,
242
261
  }, true);
@@ -256,10 +275,12 @@ module.exports = {
256
275
  data.result.metaInfo.inputs.forEach((input) => {
257
276
  if (['text', 'pineId', 'pineVersion'].includes(input.id)) return;
258
277
 
278
+ const inlineName = input.name.replace(/ /g, '_').replace(/[^a-zA-Z0-9_]/g, '');
279
+
259
280
  inputs[input.id] = {
260
281
  name: input.name,
261
- inline: input.inline || input.name.replace(/ /g, '_').replace(/[^a-zA-Z0-9_]/g, ''),
262
- internalID: input.internalID,
282
+ inline: input.inline || inlineName,
283
+ internalID: input.internalID || inlineName,
263
284
  tooltip: input.tooltip,
264
285
 
265
286
  type: input.type,
@@ -309,25 +330,74 @@ module.exports = {
309
330
 
310
331
  /**
311
332
  * @typedef {Object} User Instance of User
312
- * @property {number} id User ID
313
- * @property {string} username User username
314
- * @property {string} firstName User first name
315
- * @property {string} lastName User last name
316
- * @property {number} reputation User reputation
317
- * @property {number} following Number of following accounts
318
- * @property {number} followers Number of followers
319
- * @property {Object} notifications User's notifications
320
- * @property {number} notifications.user User notifications
321
- * @property {number} notifications.following Notification from following accounts
322
- * @property {string} session User session
323
- * @property {string} sessionHash User session hash
324
- * @property {string} privateChannel User private channel
325
- * @property {string} authToken User auth token
326
- * @property {Date} joinDate Account creation date
333
+ * @prop {number} id User ID
334
+ * @prop {string} username User username
335
+ * @prop {string} firstName User first name
336
+ * @prop {string} lastName User last name
337
+ * @prop {number} reputation User reputation
338
+ * @prop {number} following Number of following accounts
339
+ * @prop {number} followers Number of followers
340
+ * @prop {Object} notifications User's notifications
341
+ * @prop {number} notifications.user User notifications
342
+ * @prop {number} notifications.following Notification from following accounts
343
+ * @prop {string} session User session
344
+ * @prop {string} sessionHash User session hash
345
+ * @prop {string} privateChannel User private channel
346
+ * @prop {string} authToken User auth token
347
+ * @prop {Date} joinDate Account creation date
327
348
  */
328
349
 
329
350
  /**
330
- * Get a token for an user from a 'sessionid' cookie
351
+ * Get user and sessionid from username/email and password
352
+ * @function loginUser
353
+ * @param {string} username User username/email
354
+ * @param {string} password User password
355
+ * @param {boolean} [remember] Remember the session (default: false)
356
+ * @param {string} [UA] Custom UserAgent
357
+ * @returns {Promise<User>} Token
358
+ */
359
+ 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()})`,
373
+ },
374
+ }, false, formData.toString());
375
+
376
+ if (data.error) throw new Error(data.error);
377
+
378
+ const cookie = cookies.find((c) => c.includes('sessionid='));
379
+ const session = (cookie.match(/sessionid=(.*?);/) ?? [])[1];
380
+
381
+ return {
382
+ id: data.user.id,
383
+ username: data.user.username,
384
+ firstName: data.user.first_name,
385
+ lastName: data.user.last_name,
386
+ reputation: data.user.reputation,
387
+ following: data.user.following,
388
+ followers: data.user.followers,
389
+ notifications: data.user.notification_count,
390
+ session,
391
+ sessionHash: data.user.session_hash,
392
+ privateChannel: data.user.private_channel,
393
+ authToken: data.user.auth_token,
394
+ joinDate: new Date(data.user.date_joined),
395
+ };
396
+ },
397
+
398
+ /**
399
+ * Get user from 'sessionid' cookie
400
+ * @function getUser
331
401
  * @param {string} session User 'sessionid' cookie
332
402
  * @param {string} [location] Auth page location (For france: https://fr.tradingview.com/)
333
403
  * @returns {Promise<User>} Token
@@ -373,6 +443,7 @@ module.exports = {
373
443
 
374
444
  /**
375
445
  * Get user's private indicators from a 'sessionid' cookie
446
+ * @function getPrivateIndicators
376
447
  * @param {string} session User 'sessionid' cookie
377
448
  * @returns {Promise<SearchIndicatorResult[]>} Search results
378
449
  */
@@ -420,12 +491,13 @@ module.exports = {
420
491
  /**
421
492
  * User credentials
422
493
  * @typedef {Object} UserCredentials
423
- * @property {number} id User ID
424
- * @property {string} session User session ('sessionid' cookie)
494
+ * @prop {number} id User ID
495
+ * @prop {string} session User session ('sessionid' cookie)
425
496
  */
426
497
 
427
498
  /**
428
499
  * Get a chart token from a layout ID and the user credentials if the layout is not public
500
+ * @function getChartToken
429
501
  * @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
430
502
  * @param {UserCredentials} [credentials] User credentials (id + session)
431
503
  * @returns {Promise<string>} Token
@@ -435,7 +507,7 @@ module.exports = {
435
507
  const userID = creds ? credentials.id : -1;
436
508
  const session = creds ? credentials.session : null;
437
509
 
438
- const data = await request({
510
+ const { data } = await request({
439
511
  host: 'www.tradingview.com',
440
512
  path: `/chart-token/?image_url=${layout}&user_id=${userID}`,
441
513
  headers: { cookie: session ? `sessionid=${session}` : '' },
@@ -448,32 +520,33 @@ module.exports = {
448
520
 
449
521
  /**
450
522
  * @typedef {Object} DrawingPoint Drawing poitn
451
- * @property {number} time_t Point X time position
452
- * @property {number} price Point Y price position
453
- * @property {number} offset Point offset
523
+ * @prop {number} time_t Point X time position
524
+ * @prop {number} price Point Y price position
525
+ * @prop {number} offset Point offset
454
526
  */
455
527
 
456
528
  /**
457
529
  * @typedef {Object} Drawing
458
- * @property {string} id Drawing ID (Like: 'XXXXXX')
459
- * @property {string} symbol Layout market symbol (Like: 'BINANCE:BUCEUR')
460
- * @property {string} ownerSource Owner user ID (Like: 'XXXXXX')
461
- * @property {string} serverUpdateTime Drawing last update timestamp
462
- * @property {string} currencyId Currency ID (Like: 'EUR')
463
- * @property {any} unitId Unit ID
464
- * @property {string} type Drawing type
465
- * @property {DrawingPoint[]} points List of drawing points
466
- * @property {number} zorder Drawing Z order
467
- * @property {string} linkKey Drawing link key
468
- * @property {Object} state Drawing state
530
+ * @prop {string} id Drawing ID (Like: 'XXXXXX')
531
+ * @prop {string} symbol Layout market symbol (Like: 'BINANCE:BUCEUR')
532
+ * @prop {string} ownerSource Owner user ID (Like: 'XXXXXX')
533
+ * @prop {string} serverUpdateTime Drawing last update timestamp
534
+ * @prop {string} currencyId Currency ID (Like: 'EUR')
535
+ * @prop {any} unitId Unit ID
536
+ * @prop {string} type Drawing type
537
+ * @prop {DrawingPoint[]} points List of drawing points
538
+ * @prop {number} zorder Drawing Z order
539
+ * @prop {string} linkKey Drawing link key
540
+ * @prop {Object} state Drawing state
469
541
  */
470
542
 
471
543
  /**
472
544
  * Get a chart token from a layout ID and the user credentials if the layout is not public
545
+ * @function getDrawings
473
546
  * @param {string} layout The layout ID found in the layout URL (Like: 'XXXXXXXX')
474
547
  * @param {string | ''} [symbol] Market filter (Like: 'BINANCE:BTCEUR')
475
548
  * @param {UserCredentials} [credentials] User credentials (id + session)
476
- * @param {number} [chartID = 1] Chart ID
549
+ * @param {number} [chartID] Chart ID
477
550
  * @returns {Promise<Drawing[]>} Drawings
478
551
  */
479
552
  async getDrawings(layout, symbol = '', credentials = {}, chartID = 1) {
@@ -481,7 +554,7 @@ module.exports = {
481
554
  const creds = credentials.id && credentials.session;
482
555
  const session = creds ? credentials.session : null;
483
556
 
484
- const data = await request({
557
+ const { data } = await request({
485
558
  host: 'charts-storage.tradingview.com',
486
559
  path: `/charts-storage/layout/${layout}/sources?chart_id=${chartID
487
560
  }&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(/~h~/g, '').split(/~m~[0-9]{1,}~m~/g)
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/request.js CHANGED
@@ -1,37 +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<string | object | array>} 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);
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);
29
- });
30
- });
31
-
32
- req.on('error', err);
33
- req.end(content);
34
- });
35
- }
36
-
37
- module.exports = request;
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';
package/test.js CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-continue */
1
2
  /* eslint-disable no-await-in-loop */
2
3
  /* eslint-disable import/no-dynamic-require */
3
4
  /* eslint-disable no-restricted-syntax */
@@ -37,6 +38,7 @@ function success() {
37
38
  console.info('§90§30§104 ==== Starting tests ==== §0');
38
39
 
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;
40
42
  const test = require(`./tests/${file}`);
41
43
  const name = file.replace(/\.js/g, '');
42
44
  TESTS[name] = { errors: 0, warnings: 0 };
@@ -65,9 +65,10 @@ module.exports = async (log, success, warn, err, cb) => {
65
65
 
66
66
  QTY += 10;
67
67
  log('TRY WITH', QTY, '%');
68
- indicator.setOption('default_qty_value', QTY);
69
-
70
- SuperTrend.setIndicator(indicator);
68
+ setTimeout(() => {
69
+ indicator.setOption('default_qty_value', QTY);
70
+ SuperTrend.setIndicator(indicator);
71
+ }, 1000);
71
72
  });
72
73
  });
73
74
 
@@ -1,34 +0,0 @@
1
- const TradingView = require('../main');
2
-
3
- /*
4
- This example tests an indicator that sends
5
- graphic data such as 'lines', 'labels',
6
- 'boxes', 'tables', 'polygons', etc...
7
- */
8
-
9
- const client = new TradingView.Client();
10
-
11
- const chart = new client.Session.Chart();
12
-
13
- let wantedTimeframe = '5';
14
- let timeframe = null;
15
-
16
- chart.setMarket('BINANCE:BTCEUR', {
17
- timeframe: wantedTimeframe,
18
- });
19
-
20
- chart.onSymbolLoaded(() => {
21
- timeframe = wantedTimeframe;
22
- console.log(`Timeframe is now '${timeframe}'`);
23
- });
24
-
25
- chart.onUpdate(() => {
26
- console.log(`Received data on '${timeframe}' timeframe`);
27
- });
28
-
29
- setTimeout(() => {
30
- wantedTimeframe = '240';
31
- chart.setMarket('BINANCE:BTCEUR', {
32
- timeframe: wantedTimeframe,
33
- });
34
- }, 3000);
@@ -1,41 +0,0 @@
1
- const TradingView = require('../main');
2
-
3
- if (!process.argv[2]) throw Error('Please specify your \'sessionid\' cookie');
4
-
5
- const client = new TradingView.Client({
6
- token: process.argv[2],
7
- });
8
-
9
- const chart = new client.Session.Chart();
10
- chart.setMarket('NASDAQ:AAPL', {
11
- type: 'Renko',
12
- timeframe: '1',
13
- inputs: {
14
- source: 'close',
15
- sources: 'Close',
16
- boxSize: 3,
17
- style: 'Traditional',
18
- atrLength: 14,
19
- wicks: true,
20
- },
21
- });
22
-
23
- TradingView.searchIndicator('CM_Ultimate_MA_MTF_V2').then(async (indicator) => {
24
- console.log(
25
- '*** Indicator information\n',
26
- indicator[0].id,
27
- );
28
- const pineIndicator = await indicator[0].get();
29
- const study = new chart.Study(pineIndicator);
30
- study.onUpdate(() => {
31
- console.log(
32
- '\n*** Chart time and close:\n',
33
- chart.periods[0].time,
34
- chart.periods[0].close,
35
- );
36
- console.log(
37
- '\n*** Indicator values:\n',
38
- study.periods[0].MultiTimeframe_Moving_Avg,
39
- );
40
- });
41
- });
@@ -1,24 +0,0 @@
1
- const TradingView = require('../main');
2
-
3
- module.exports = async (log, success, warn, err, cb) => {
4
- const client = new TradingView.Client();
5
-
6
- client.onError((...error) => {
7
- err('Client error', error);
8
- throw new Error('Client error');
9
- });
10
-
11
- const chart = new client.Session.Chart();
12
- chart.setMarket('BINANCE:BTCEUR', {
13
- timeframe: '60',
14
- });
15
-
16
- chart.onError((...error) => {
17
- err('Chart error', error);
18
- throw new Error('Chart error');
19
- });
20
-
21
- chart.delete();
22
- await client.end();
23
- cb();
24
- };