@mathieuc/tradingview 2.0.7 → 3.0.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.
@@ -0,0 +1,41 @@
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
+ });
package/main.js CHANGED
@@ -1,352 +1,9 @@
1
- const WebSocket = require('ws');
2
- const {
3
- search, getScreener, getTA, getIndicator,
4
- getUser, getChartToken, getDrawings,
5
- } = require('./miscRequests');
6
-
7
- let onPacket = () => null;
8
-
9
- function parse(str) {
10
- const packets = str.replace(/~h~/g, '').split(/~m~[0-9]{1,}~m~/g).map((p) => {
11
- if (!p) return false;
12
- try {
13
- return JSON.parse(p);
14
- } catch (error) {
15
- console.warn('Cant parse', p);
16
- return false;
17
- }
18
- }).filter((p) => p);
19
-
20
- packets.forEach((packet) => {
21
- if (packet.m === 'protocol_error') {
22
- return onPacket({
23
- type: 'error',
24
- syntax: packet.p[0],
25
- });
26
- }
27
-
28
- if (packet.m && packet.p) {
29
- return onPacket({
30
- type: packet.m,
31
- session: packet.p[0],
32
- data: packet.p[1],
33
- });
34
- }
35
-
36
- if (typeof packet === 'number') return onPacket({ type: 'ping', ping: packet });
37
-
38
- return onPacket({ type: 'info', ...packet });
39
- });
40
- }
41
-
42
- function genSession() {
43
- let r = '';
44
- const c = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
45
- for (let i = 0; i < 12; i += 1) r += c.charAt(Math.floor(Math.random() * c.length));
46
- return `qs_${r}`;
47
- }
48
-
49
- module.exports = (autoInit = true) => {
50
- const callbacks = {
51
- connected: [],
52
- disconnected: [],
53
- logged: [],
54
- subscribed: [],
55
- ping: [],
56
- price: [],
57
- data: [],
58
-
59
- error: [],
60
- event: [],
61
- };
62
-
63
- const chartEventNames = [
64
- 'du', 'timescale_update',
65
- 'series_loading', 'series_completed', 'series_error',
66
- 'symbol_resolved', 'symbol_error',
67
- 'study_loading', 'study_error',
68
- ];
69
- const chartCBs = {};
70
-
71
- function handleEvent(ev, ...data) {
72
- callbacks[ev].forEach((e) => e(...data));
73
- callbacks.event.forEach((e) => e(ev, ...data));
74
- }
75
-
76
- function handleError(...msgs) {
77
- if (callbacks.error.length === 0) console.error(...msgs);
78
- else handleEvent('error', ...msgs);
79
- }
80
-
81
- const ws = new WebSocket('wss://widgetdata.tradingview.com/socket.io/websocket', {
82
- origin: 'https://s.tradingview.com',
83
- });
84
-
85
- let logged = false;
86
- /** ID of the quote session */
87
- let sessionId = '';
88
-
89
- /** List of subscribed symbols */
90
- let subscribed = [];
91
-
92
- /** Websockets status calls */
93
- let isEnded = false;
94
-
95
- /**
96
- * Send a custom packet
97
- * @param {string} t Packet type
98
- * @param {string[]} p Packet data
99
- * @example
100
- * // Subscribe manualy to BTCEUR
101
- * send('quote_add_symbols', [sessionId, 'BTCEUR']);
102
- */
103
- function send(t, p = []) {
104
- if (!sessionId) return;
105
-
106
- const msg = JSON.stringify({ m: t, p });
107
- ws.send(`~m~${msg.length}~m~${msg}`);
108
- }
109
-
110
- ws.on('open', () => {
111
- sessionId = genSession();
112
- handleEvent('connected');
113
- });
114
-
115
- ws.on('close', () => {
116
- logged = false;
117
- sessionId = '';
118
- handleEvent('disconnected');
119
- });
120
-
121
- ws.on('message', parse);
122
-
123
- onPacket = (packet) => {
124
- if (packet.type === 'ping') {
125
- const pingStr = `~h~${packet.ping}`;
126
- ws.send(`~m~${pingStr.length}~m~${pingStr}`);
127
- handleEvent('ping', packet.ping);
128
- return;
129
- }
130
-
131
- if (packet.type === 'quote_completed' && packet.data) {
132
- handleEvent('subscribed', packet.data);
133
- return;
134
- }
135
-
136
- if (packet.type === 'qsd' && packet.data.n && packet.data.v.lp) {
137
- handleEvent('price', {
138
- symbol: packet.data.n,
139
- price: packet.data.v.lp,
140
- });
141
-
142
- return;
143
- }
144
-
145
- if (chartEventNames.includes(packet.type) && chartCBs[packet.session]) {
146
- chartCBs[packet.session](packet);
147
- return;
148
- }
149
-
150
- if (!logged && packet.type === 'info') {
151
- if (autoInit) {
152
- send('set_auth_token', ['unauthorized_user_token']);
153
- send('quote_create_session', [sessionId]);
154
- send('quote_set_fields', [sessionId, 'lp']);
155
-
156
- subscribed.forEach((symbol) => send('quote_add_symbols', [sessionId, symbol]));
157
- }
158
-
159
- handleEvent('logged', packet);
160
- return;
161
- }
162
-
163
- if (packet.type === 'error') {
164
- handleError(`Market API critical error: ${packet.syntax}`);
165
- ws.close();
166
- return;
167
- }
168
-
169
- handleEvent('data', packet);
170
- };
171
-
172
- return {
173
- /** Event listener
174
- * @param { 'connected' | 'disconnected' | 'logged'
175
- * | 'subscribed' | 'price' | 'data' | 'error' | 'ping' } event Event
176
- * @param {(...data: object) => null} cb Callback
177
- */
178
- on(event, cb) {
179
- if (!callbacks[event]) {
180
- console.log('Wrong event:', event);
181
- console.log('Available events:', Object.keys(callbacks));
182
- return;
183
- }
184
-
185
- callbacks[event].push(cb);
186
- },
187
-
188
- /**
189
- * Close the websocket connection
190
- * @return {Promise<void>} When websocket is closed
191
- */
192
- end() {
193
- return new Promise((cb) => {
194
- isEnded = true;
195
- ws.close();
196
- cb();
197
- });
198
- },
199
-
200
- getUser,
201
- getChartToken,
202
- getDrawings,
203
- search,
204
- getScreener,
205
- getTA,
206
- subscribed,
207
-
208
- /**
209
- * Unsubscribe to a market
210
- * @param {string} symbol Market symbol (Example: BTCEUR or COINBASE:BTCEUR)
211
- */
212
- subscribe(symbol) {
213
- if (subscribed.includes(symbol)) return;
214
- send('quote_add_symbols', [sessionId, symbol]);
215
- subscribed.push(symbol);
216
- },
217
-
218
- /**
219
- * Unsubscribe from a market
220
- * @param {string} symbol Market symbol (Example: BTCEUR or COINBASE:BTCEUR)
221
- */
222
- unsubscribe(symbol) {
223
- if (!subscribed.includes(symbol)) return;
224
- send('quote_remove_symbols', [sessionId, symbol]);
225
- subscribed = subscribed.filter((s) => s !== symbol);
226
- },
227
-
228
- /**
229
- * @typedef {Object} IndicatorInfos Indicator infos
230
- * @property {string} id ID of the indicator (Like: XXX;XXXXXXXXXXXXXXXXXXXXX)
231
- * @property {string} version Wanted version of the indicator
232
- * @property {(string | number | boolean | null)[]} [settings] Indicator settings value
233
- *
234
- * @typedef {Object} ChartInfos
235
- * @property {string} [session] User 'sessionid' cookie
236
- * @property {string} symbol Market symbol (Example: BTCEUR or COINBASE:BTCEUR)
237
- * @property { '1' | '3' | '5' | '15' | '30' | '45'
238
- * | '60' | '120' | '180' | '240'
239
- * | '1D' | '1W' | '1M'
240
- * } [period] Period
241
- * @property {number} [range] Number of loaded periods
242
- * @property {string} [timezone] Timezone in 'Europe/Paris' format
243
- * @property {IndicatorInfos[]} [indicators] List of indicators
244
- */
245
-
246
- /**
247
- * @typedef {Object} Period List of prices / indicator values
248
- * @property {number} $time
249
- * @property {{
250
- * time: number, open: number, close: number,
251
- * max: number, min: number, change: number,
252
- * }} $prices
253
- */
254
-
255
- /**
256
- * Init a chart instance
257
- * @param {ChartInfos} chart
258
- * @param {{(prices: Period[]): null}} onUpdate List of periods starting from the lastest
259
- */
260
- async initChart(chart, onUpdate) {
261
- const chartSession = genSession();
262
- const periods = [];
263
- const indicators = await Promise.all(
264
- (chart.indicators || []).map((i) => getIndicator(i.id, i.version, i.settings)),
265
- );
266
-
267
- function updatePeriods(packet) {
268
- const newData = packet.data;
269
-
270
- Object.keys(newData).forEach((type) => {
271
- (newData[type].s || newData[type].st || []).forEach((p) => {
272
- if (!periods[p.i]) periods[p.i] = {};
273
-
274
- if (newData[type].s) {
275
- [periods[p.i].$time] = p.v;
276
-
277
- periods[p.i][type] = {
278
- open: p.v[1],
279
- close: p.v[4],
280
- max: p.v[2],
281
- min: p.v[3],
282
- change: Math.round(p.v[5] * 100) / 100,
283
- };
284
- }
285
-
286
- if (newData[type].st) {
287
- const period = {};
288
- const indicator = indicators[parseInt(type, 10)];
289
-
290
- p.v.forEach((val, i) => {
291
- if (i === 0) return;
292
- if (indicator.plots[`plot_${i - 1}`]) period[indicator.plots[`plot_${i - 1}`]] = val;
293
- else period[`_plot_${i - 1}`] = val;
294
- });
295
- periods[p.i][chart.indicators[parseInt(type, 10)].name || `st${type}`] = period;
296
- }
297
- });
298
- });
299
- }
300
-
301
- chartCBs[chartSession] = (packet) => {
302
- if (isEnded) return;
303
-
304
- if (['timescale_update', 'du'].includes(packet.type)) {
305
- updatePeriods(packet);
306
- onUpdate([...periods].reverse());
307
- return;
308
- }
309
-
310
- if (packet.type.endsWith('_error')) {
311
- handleError(`Error on '${chart.symbol}' (${chartSession}) chart: "${packet.type}"`);
312
- }
313
- };
314
-
315
- if (chart.session) send('set_auth_token', [(await getUser(chart.session)).authToken]);
316
- send('chart_create_session', [chartSession, '']);
317
- if (chart.timezone) send('switch_timezone', [chartSession, chart.timezone]);
318
- send('resolve_symbol', [chartSession, 'sds_sym_1', `={"symbol":"${chart.symbol || 'BTCEUR'}","adjustment":"splits"}`]);
319
- send('create_series', [chartSession, '$prices', 's1', 'sds_sym_1', (chart.period || '240'), (chart.range || 100), '']);
320
-
321
- indicators.forEach(async (indicator, i) => {
322
- const pineInfos = {
323
- pineId: indicator.pineId,
324
- pineVersion: indicator.pineVersion,
325
- text: indicator.script,
326
- };
327
-
328
- Object.keys(indicator.inputs).forEach((inputID, inp) => {
329
- const input = indicator.inputs[inputID];
330
- if (input.type === 'bool' && typeof input.value !== 'boolean') handleError(`Input '${input.name}' (${inp}) must be a boolean !`);
331
- if (input.type === 'integer' && typeof input.value !== 'number') handleError(`Input '${input.name}' (${inp}) must be a number !`);
332
- if (input.type === 'float' && typeof input.value !== 'number') handleError(`Input '${input.name}' (${inp}) must be a number !`);
333
- if (input.type === 'text' && typeof input.value !== 'string') handleError(`Input '${input.name}' (${inp}) must be a string !`);
334
- if (input.options && !input.options.includes(input.value)) {
335
- handleError(`Input '${input.name}' (${inp}) must be one of these values:`, input.options);
336
- }
337
-
338
- pineInfos[inputID] = {
339
- v: input.value,
340
- f: input.isFake,
341
- t: input.type,
342
- };
343
- });
344
-
345
- send('create_study', [chartSession, `${i}`, 'st1', '$prices', 'Script@tv-scripting-101!', pineInfos]);
346
- });
347
- },
348
-
349
- send,
350
- sessionId,
351
- };
352
- };
1
+ const miscRequests = require('./src/miscRequests');
2
+ const Client = require('./src/client');
3
+ const BuiltInIndicator = require('./src/classes/BuiltInIndicator');
4
+ const PineIndicator = require('./src/classes/PineIndicator');
5
+
6
+ module.exports = { ...miscRequests };
7
+ module.exports.Client = Client;
8
+ module.exports.BuiltInIndicator = BuiltInIndicator;
9
+ module.exports.PineIndicator = PineIndicator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mathieuc/tradingview",
3
- "version": "2.0.7",
3
+ "version": "3.0.0",
4
4
  "description": "Tradingview instant stocks API, indicator alerts, trading bot, and more !",
5
5
  "main": "main.js",
6
6
  "scripts": {
@@ -11,6 +11,10 @@
11
11
  "test-strat-alerts": "node ./tests/alerts/strategyAlert.js",
12
12
  "test": "npm run test-prices"
13
13
  },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/Mathieu2301/TradingView-API.git"
17
+ },
14
18
  "keywords": [
15
19
  "tradingwiew",
16
20
  "market",
@@ -24,11 +28,15 @@
24
28
  "author": "Mathieu Colmon",
25
29
  "license": "ISC",
26
30
  "dependencies": {
31
+ "jszip": "^3.7.1",
27
32
  "ws": "^7.4.3"
28
33
  },
29
34
  "devDependencies": {
35
+ "@babel/eslint-parser": "^7.15.7",
36
+ "@mathieuc/console": "^1.0.1",
30
37
  "eslint": "^7.25.0",
31
38
  "eslint-config-airbnb-base": "^14.2.1",
32
- "eslint-plugin-import": "^2.22.1"
39
+ "eslint-plugin-import": "^2.22.1",
40
+ "jsdoc-to-markdown": "^7.1.0"
33
41
  }
34
42
  }