@mathieuc/tradingview 2.0.5 → 3.0.0-pre

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/miscRequests.js DELETED
@@ -1,285 +0,0 @@
1
- const https = require('https');
2
-
3
- const indicators = ['Recommend.Other', 'Recommend.All', 'Recommend.MA'];
4
-
5
- function fetchScanData(tickers = [], type = '', columns = []) {
6
- return new Promise((cb, err) => {
7
- const req = https.request({
8
- method: 'POST',
9
- hostname: 'scanner.tradingview.com',
10
- path: `/${type}/scan`,
11
- headers: {
12
- 'Content-Type': 'application/json',
13
- },
14
- }, (res) => {
15
- let data = '';
16
- res.on('data', (c) => { data += c; });
17
- res.on('end', () => {
18
- if (!data.startsWith('{')) {
19
- err(new Error('Wrong screener or symbol'));
20
- return;
21
- }
22
- try {
23
- cb(JSON.parse(data));
24
- } catch (error) {
25
- err(new Error('Can\'t parse server response'));
26
- }
27
- });
28
- });
29
-
30
- req.on('error', err);
31
- req.end(JSON.stringify({ symbols: { tickers }, columns }));
32
- });
33
- }
34
-
35
- /**
36
- * @typedef {number} advice
37
- *
38
- * @typedef {{ Other: advice, All: advice, MA: advice }} Period
39
- *
40
- * @typedef {{
41
- * '1': Period,
42
- * '5': Period,
43
- * '15': Period,
44
- * '60': Period,
45
- * '240': Period,
46
- * '1D': Period,
47
- * '1W': Period,
48
- * '1M': Period,
49
- * }} Periods
50
- *
51
- * @typedef {string | 'forex' | 'crypto'
52
- * | 'america' | 'australia' | 'canada' | 'egypt'
53
- * | 'germany' | 'india' | 'israel' | 'italy'
54
- * | 'luxembourg' | 'poland' | 'sweden' | 'turkey'
55
- * | 'uk' | 'vietnam'} screener
56
- * You can use `getScreener(exchange)` function for non-forex and non-crypto markets.
57
- */
58
-
59
- module.exports = {
60
- /**
61
- * @param {string} exchange Example: BINANCE, EURONEXT, NASDAQ
62
- * @returns {screener}
63
- */
64
- getScreener(exchange) {
65
- const e = exchange.toUpperCase();
66
- if (['NASDAQ', 'NYSE', 'NYSE ARCA', 'OTC'].includes(e)) return 'america';
67
- if (['ASX'].includes(e)) return 'australia';
68
- if (['TSX', 'TSXV', 'CSE', 'NEO'].includes(e)) return 'canada';
69
- if (['EGX'].includes(e)) return 'egypt';
70
- if (['FWB', 'SWB', 'XETR'].includes(e)) return 'germany';
71
- if (['BSE', 'NSE'].includes(e)) return 'india';
72
- if (['TASE'].includes(e)) return 'israel';
73
- if (['MIL', 'MILSEDEX'].includes(e)) return 'italy';
74
- if (['LUXSE'].includes(e)) return 'luxembourg';
75
- if (['NEWCONNECT'].includes(e)) return 'poland';
76
- if (['NGM'].includes(e)) return 'sweden';
77
- if (['BIST'].includes(e)) return 'turkey';
78
- if (['LSE', 'LSIN'].includes(e)) return 'uk';
79
- if (['HNX'].includes(e)) return 'vietnam';
80
- return exchange.toLowerCase();
81
- },
82
-
83
- /** Get technical analysis
84
- * @param {screener} screener
85
- * @param {string} id Full market id (Example: COINBASE:BTCEUR)
86
- * @returns {Promise<Periods>} results
87
- */
88
- async getTA(screener, id) {
89
- const advice = {};
90
-
91
- const cols = ['1', '5', '15', '60', '240', '1D', '1W', '1M']
92
- .map((t) => indicators.map((i) => (t !== '1D' ? `${i}|${t}` : i)))
93
- .flat();
94
-
95
- const rs = await fetchScanData([id], screener, cols);
96
- if (!rs.data || !rs.data[0]) return false;
97
-
98
- rs.data[0].d.forEach((val, i) => {
99
- const [name, period] = cols[i].split('|');
100
- const pName = period || '1D';
101
- if (!advice[pName]) advice[pName] = {};
102
- advice[pName][name.split('.').pop()] = Math.round(val * 1000) / 500;
103
- });
104
-
105
- return advice;
106
- },
107
-
108
- /**
109
- * @typedef {Object} SearchResult
110
- * @property {string} id
111
- * @property {string} exchange
112
- * @property {string} fullExchange
113
- * @property {string} screener
114
- * @property {string} symbol
115
- * @property {string} description
116
- * @property {string} type
117
- * @property {() => Promise<Periods>} getTA
118
- */
119
-
120
- /**
121
- * @param {string} search Search a symbol
122
- * @param {'stock' | 'futures' | 'forex' | 'cfd' | 'crypto' | 'index' | 'economic'} filter
123
- * @returns {Promise<SearchResult[]>} Search results
124
- */
125
- async search(search, filter = '') {
126
- return new Promise((cb, err) => {
127
- https.get({
128
- host: 'symbol-search.tradingview.com',
129
- path: `/symbol_search/?text=${search.replace(/ /g, '%20')}&type=${filter}`,
130
- origin: 'https://www.tradingview.com',
131
- }, (res) => {
132
- let rs = '';
133
- res.on('data', (d) => { rs += d; });
134
- res.on('end', () => {
135
- try {
136
- rs = JSON.parse(rs);
137
- } catch (e) {
138
- err(new Error('Can\'t parse server response'));
139
- return;
140
- }
141
-
142
- cb(rs.map((s) => {
143
- const exchange = s.exchange.split(' ')[0];
144
- const id = `${exchange}:${s.symbol}`;
145
-
146
- const screener = (['forex', 'crypto'].includes(s.type)
147
- ? s.type
148
- : this.getScreener(exchange)
149
- );
150
-
151
- return {
152
- id,
153
- exchange,
154
- fullExchange: s.exchange,
155
- screener,
156
- symbol: s.symbol,
157
- description: s.description,
158
- type: s.type,
159
- getTA: () => this.getTA(screener, id),
160
- };
161
- }));
162
- });
163
-
164
- res.on('error', err);
165
- });
166
- });
167
- },
168
-
169
- /**
170
- * @typedef {Object} indicatorInput
171
- * @property {string} name
172
- * @property {string} inline Inline name
173
- * @property { 'text' | 'source' | 'integer' | 'float' | 'resolution' | 'bool' } type
174
- * @property {string | number | boolean} value
175
- * @property {string | number | boolean} defVal
176
- * @property {boolean} hidden
177
- * @property {boolean} isFake
178
- * @property {string[]} [options]
179
- */
180
-
181
- /**
182
- * @typedef {Object} Indicator
183
- * @property {string} pineId Indicator ID
184
- * @property {string} pineVersion Indicator version
185
- * @property {string} description Indicator description
186
- * @property {string} shortDescription Indicator short description
187
- * @property {Object<string, indicatorInput>} inputs Indicator inputs
188
- * @property {Object<string, string>} plots Indicator plots
189
- * @property {string} script Indicator script
190
- */
191
-
192
- /**
193
- * Get an indicator
194
- * @param {string} id Indicator ID (Like: PUB;XXXXXXXXXXXXXXXXXXXXX)
195
- * @param {string} version Wanted version of the indicator
196
- * @returns {Promise<Indicator>} Indicator
197
- */
198
- async getIndicator(id, version, settings = []) {
199
- return new Promise((cb, err) => {
200
- https.get(`https://pine-facade.tradingview.com/pine-facade/translate/${id}/${version}`, (res) => {
201
- let rs = '';
202
- res.on('data', (d) => { rs += d; });
203
- res.on('end', () => {
204
- try {
205
- rs = JSON.parse(rs);
206
- } catch (e) {
207
- err(new Error('Inexistent or unsupported indicator'));
208
- return;
209
- }
210
-
211
- if (!rs.success || !rs.result.metaInfo || !rs.result.metaInfo.inputs) {
212
- err(new Error('Inexistent or unsupported indicator'));
213
- return;
214
- }
215
-
216
- const inputs = {};
217
-
218
- rs.result.metaInfo.inputs.forEach((input) => {
219
- if (['text', 'pineId', 'pineVersion'].includes(input.id)) return;
220
- const inline = input.inline || input.name.replace(/ /g, '_').replace(/[^a-zA-Z0-9]/g, '');
221
-
222
- const i = parseInt(input.id.replace(/[^0-9]/g, ''), 10);
223
-
224
- inputs[input.id] = {
225
- name: input.name,
226
- type: input.type,
227
- value: settings[i] ?? input.defval,
228
- defVal: input.defval,
229
- hidden: !!input.isHidden,
230
- isFake: !!input.isFake,
231
- inline,
232
- };
233
-
234
- if (input.options) inputs[input.id].options = input.options;
235
- });
236
-
237
- const plots = {};
238
-
239
- Object.keys(rs.result.metaInfo.styles).forEach((plotId) => {
240
- plots[plotId] = rs.result.metaInfo.styles[plotId].title.replace(/ /g, '_').replace(/[^a-zA-Z0-9]/g, '');
241
- });
242
-
243
- cb({
244
- pineId: id,
245
- pineVersion: version,
246
- description: rs.result.metaInfo.description,
247
- shortDescription: rs.result.metaInfo.shortDescription,
248
- inputs,
249
- plots,
250
- script: rs.result.ilTemplate,
251
- });
252
- });
253
-
254
- res.on('error', err);
255
- });
256
- });
257
- },
258
-
259
- /**
260
- * Get a token for an user from a 'sessionid' cookie
261
- * @param {string} session User 'sessionid' cookie
262
- * @param {string} [location] Auth page location (For france: https://fr.tradingview.com/)
263
- * @returns {Promise<string>} Token
264
- */
265
- async getUserToken(session, location = 'https://www.tradingview.com/') {
266
- return new Promise((cb, err) => {
267
- https.get(location, {
268
- headers: { cookie: `sessionid=${session}` },
269
- }, (res) => {
270
- let rs = '';
271
- res.on('data', (d) => { rs += d; });
272
- res.on('end', async () => {
273
- if (res.headers.location && location !== res.headers.location) {
274
- cb(await module.exports.getUserToken(session, res.headers.location));
275
- return;
276
- }
277
- if (rs.includes('auth_token')) cb(/"auth_token":"(.*?)"/g.exec(rs)[1]);
278
- else err(new Error('Wrong or expired sessionid'));
279
- });
280
-
281
- res.on('error', err);
282
- }).end();
283
- });
284
- },
285
- };