@mathieuc/tradingview 3.0.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +6 -0
- package/README.md +29 -3
- package/docs/DOCS.md +3 -0
- package/examples/AllPrivateIndicators.js +4 -4
- package/examples/BuiltInIndicator.js +1 -1
- package/examples/CustomChartType.js +1 -0
- package/examples/Errors.js +147 -153
- package/examples/FakeReplayMode.js +41 -0
- package/examples/FromToData.js +29 -0
- package/examples/GetDrawings.js +26 -0
- package/examples/GraphicIndicator.js +7 -5
- package/examples/PinePermManage.js +57 -0
- package/examples/ReplayMode.js +97 -0
- package/examples/UserLogin.js +16 -0
- package/main.js +2 -0
- package/package.json +6 -9
- package/src/FormData.js +36 -0
- package/src/chart/session.js +205 -24
- package/src/chart/study.js +68 -68
- package/src/classes/BuiltInIndicator.js +7 -1
- package/src/classes/PineIndicator.js +7 -7
- package/src/classes/PinePermManager.js +143 -0
- package/src/client.js +15 -10
- package/src/miscRequests.js +144 -101
- package/src/protocol.js +7 -1
- package/src/quote/session.js +1 -0
- package/src/request.js +37 -0
- package/src/types.js +6 -2
- package/src/utils.js +6 -0
- package/test.js +58 -147
- package/tests/1. Search.js +18 -0
- package/tests/2. QuoteSession.js +54 -0
- package/tests/3. SimpleChart.js +61 -0
- package/tests/4. Indicators.js +100 -0
- package/tests/5. BuiltInIndicator.js +41 -0
- package/tests/6. FakeReplayMode.js +59 -0
- package/tests/7. ReplayMode.js +51 -0
- package/tests/8. CustomChartTypes.js +115 -0
- package/tests/9. AllErrors.js +146 -0
- package/.github/FUNDING.yml +0 -1
- package/examples/_RenkoIndicator.js +0 -41
- package/tests/alerts/discordWH.js +0 -76
- package/tests/alerts/drawings.js +0 -41
- package/tests/alerts/envLoader.js +0 -11
- package/tests/alerts/manualAlert.js +0 -77
- package/tests/alerts/sentNotifs.js +0 -16
- package/tests/alerts/strategyAlert.js +0 -94
- package/tests/analysis.js +0 -13
- package/tests/indicator.js +0 -42
- package/tests/prices.js +0 -33
- package/tests/strategy.js +0 -56
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const TradingView = require('../main');
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
This example tests the real replay
|
|
5
|
+
mode by fetching indicator data and
|
|
6
|
+
stores it in a 'periods' variable
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const config = {
|
|
10
|
+
symbol: 'BINANCE:BTCEUR',
|
|
11
|
+
timeframe: 'D',
|
|
12
|
+
startFrom: Math.round(Date.now() / 1000) - 86400 * 7, // Seven days before now
|
|
13
|
+
// startFrom: 1600000000,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
console.log('----- Testing ReplayMode: -----');
|
|
17
|
+
|
|
18
|
+
const client = new TradingView.Client();
|
|
19
|
+
const chart = new client.Session.Chart();
|
|
20
|
+
|
|
21
|
+
chart.setMarket(config.symbol, {
|
|
22
|
+
timeframe: config.timeframe,
|
|
23
|
+
replay: config.startFrom,
|
|
24
|
+
range: 1,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// chart.onReplayLoaded(() => {
|
|
28
|
+
// console.log('STARTING REPLAY MODE');
|
|
29
|
+
// chart.replayStart(1000);
|
|
30
|
+
|
|
31
|
+
// // setTimeout(() => {
|
|
32
|
+
// // console.log('STOPPING REPLAY MODE');
|
|
33
|
+
// // chart.replayStop();
|
|
34
|
+
// // }, 7000);
|
|
35
|
+
// });
|
|
36
|
+
|
|
37
|
+
let loading = 0;
|
|
38
|
+
const indicators = [];
|
|
39
|
+
const periods = {};
|
|
40
|
+
|
|
41
|
+
let interval = NaN;
|
|
42
|
+
|
|
43
|
+
async function step() {
|
|
44
|
+
const period = { ...chart.periods[0] };
|
|
45
|
+
|
|
46
|
+
const times = Object.keys(periods);
|
|
47
|
+
const intrval = times[times.length - 1] - times[times.length - 2];
|
|
48
|
+
if (Number.isNaN(interval) && times.length >= 2) interval = intrval;
|
|
49
|
+
|
|
50
|
+
if (!Number.isNaN(interval) && interval !== intrval) {
|
|
51
|
+
throw new Error(`Wrong interval: ${intrval} (should be ${interval})`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
indicators.forEach(([n, i]) => {
|
|
55
|
+
const plots = { ...i.periods[0] };
|
|
56
|
+
delete plots.$time;
|
|
57
|
+
period[n] = { plots };
|
|
58
|
+
|
|
59
|
+
Object.keys(i.graphic).forEach((g) => {
|
|
60
|
+
if (!i.graphic[g].length) return;
|
|
61
|
+
if (!period[n].graphics) period[n].graphics = {};
|
|
62
|
+
period[n].graphics[g] = i.graphic[g];
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
periods[period.time] = period;
|
|
67
|
+
|
|
68
|
+
console.log('Next ->', period.time, times.length);
|
|
69
|
+
|
|
70
|
+
await chart.replayStep(1);
|
|
71
|
+
step();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
chart.onReplayEnd(async () => {
|
|
75
|
+
await client.end();
|
|
76
|
+
console.log('Done !', Object.keys(periods).length);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
async function addIndicator(name, pineId, options = {}) {
|
|
80
|
+
loading += 1;
|
|
81
|
+
|
|
82
|
+
const indic = pineId.includes('@')
|
|
83
|
+
? new TradingView.BuiltInIndicator(pineId)
|
|
84
|
+
: await TradingView.getIndicator(pineId);
|
|
85
|
+
Object.keys(options).forEach((o) => { indic.setOption(o, options[o]); });
|
|
86
|
+
|
|
87
|
+
const std = new chart.Study(indic);
|
|
88
|
+
|
|
89
|
+
std.onReady(() => {
|
|
90
|
+
indicators.push([name, std]);
|
|
91
|
+
if (loading === indicators.length) step();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
addIndicator('Volume', 'Volume@tv-basicstudies-144');
|
|
96
|
+
addIndicator('EMA_50', 'STD;EMA', { Length: 50 });
|
|
97
|
+
addIndicator('EMA_200', 'STD;EMA', { Length: 200 });
|
|
@@ -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/main.js
CHANGED
|
@@ -2,8 +2,10 @@ const miscRequests = require('./src/miscRequests');
|
|
|
2
2
|
const Client = require('./src/client');
|
|
3
3
|
const BuiltInIndicator = require('./src/classes/BuiltInIndicator');
|
|
4
4
|
const PineIndicator = require('./src/classes/PineIndicator');
|
|
5
|
+
const PinePermManager = require('./src/classes/PinePermManager');
|
|
5
6
|
|
|
6
7
|
module.exports = { ...miscRequests };
|
|
7
8
|
module.exports.Client = Client;
|
|
8
9
|
module.exports.BuiltInIndicator = BuiltInIndicator;
|
|
9
10
|
module.exports.PineIndicator = PineIndicator;
|
|
11
|
+
module.exports.PinePermManager = PinePermManager;
|
package/package.json
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mathieuc/tradingview",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Tradingview instant stocks API, indicator alerts, trading bot, and more !",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test
|
|
8
|
-
"test-analysis": "node ./tests/analysis.js",
|
|
9
|
-
"test-indicator": "node ./tests/indicator.js",
|
|
10
|
-
"test-manual-alerts": "node ./tests/alerts/manualAlert.js",
|
|
11
|
-
"test-strat-alerts": "node ./tests/alerts/strategyAlert.js",
|
|
12
|
-
"test": "npm run test-prices"
|
|
7
|
+
"test": "node test"
|
|
13
8
|
},
|
|
14
9
|
"repository": {
|
|
15
10
|
"type": "git",
|
|
16
11
|
"url": "git+https://github.com/Mathieu2301/TradingView-API.git"
|
|
17
12
|
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=14.0.0"
|
|
15
|
+
},
|
|
18
16
|
"keywords": [
|
|
19
17
|
"tradingwiew",
|
|
20
18
|
"market",
|
|
@@ -36,7 +34,6 @@
|
|
|
36
34
|
"@mathieuc/console": "^1.0.1",
|
|
37
35
|
"eslint": "^7.25.0",
|
|
38
36
|
"eslint-config-airbnb-base": "^14.2.1",
|
|
39
|
-
"eslint-plugin-import": "^2.22.1"
|
|
40
|
-
"jsdoc-to-markdown": "^7.1.0"
|
|
37
|
+
"eslint-plugin-import": "^2.22.1"
|
|
41
38
|
}
|
|
42
39
|
}
|
package/src/FormData.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
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/chart/session.js
CHANGED
|
@@ -53,17 +53,20 @@ const ChartTypes = {
|
|
|
53
53
|
* @prop {number} close Period close value
|
|
54
54
|
* @prop {number} max Period max value
|
|
55
55
|
* @prop {number} min Period min value
|
|
56
|
-
* @prop {number}
|
|
56
|
+
* @prop {number} volume Period volume value
|
|
57
57
|
*/
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* @typedef {Object} Subsession
|
|
61
61
|
* @prop {string} id Subsession ID (ex: 'regular')
|
|
62
62
|
* @prop {string} description Subsession description (ex: 'Regular')
|
|
63
|
-
* @prop {
|
|
63
|
+
* @prop {boolean} private If private
|
|
64
64
|
* @prop {string} session Session (ex: '24x7')
|
|
65
|
+
* @prop {string} session-correction Session correction
|
|
65
66
|
* @prop {string} session-display Session display (ex: '24x7')
|
|
66
|
-
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
67
70
|
* @typedef {Object} MarketInfos
|
|
68
71
|
* @prop {string} series_id Used series (ex: 'ser_1')
|
|
69
72
|
* @prop {string} base_currency Base currency (ex: 'BTC')
|
|
@@ -91,7 +94,7 @@ const ChartTypes = {
|
|
|
91
94
|
* @prop {number} minmove2 Minimum move value 2
|
|
92
95
|
* @prop {string} timezone Used timezone
|
|
93
96
|
* @prop {boolean} is_replayable If the replay mode is available
|
|
94
|
-
* @prop {boolean} has_adjustment If the adjustment mode is enabled
|
|
97
|
+
* @prop {boolean} has_adjustment If the adjustment mode is enabled
|
|
95
98
|
* @prop {boolean} has_extended_hours Has extended hours
|
|
96
99
|
* @prop {string} bar_source Bar source
|
|
97
100
|
* @prop {string} bar_transform Bar transform
|
|
@@ -112,7 +115,14 @@ const ChartTypes = {
|
|
|
112
115
|
* @param {import('../client').ClientBridge} client
|
|
113
116
|
*/
|
|
114
117
|
module.exports = (client) => class ChartSession {
|
|
115
|
-
#
|
|
118
|
+
#chartSessionID = genSessionID('cs');
|
|
119
|
+
|
|
120
|
+
#replaySessionID = genSessionID('rs');
|
|
121
|
+
|
|
122
|
+
#replayMode = false;
|
|
123
|
+
|
|
124
|
+
/** @type {Object<string, (): any>} */
|
|
125
|
+
#replayOKCB = {};
|
|
116
126
|
|
|
117
127
|
/** Parent client */
|
|
118
128
|
#client = client;
|
|
@@ -147,6 +157,11 @@ module.exports = (client) => class ChartSession {
|
|
|
147
157
|
symbolLoaded: [],
|
|
148
158
|
update: [],
|
|
149
159
|
|
|
160
|
+
replayLoaded: [],
|
|
161
|
+
replayPoint: [],
|
|
162
|
+
replayResolution: [],
|
|
163
|
+
replayEnd: [],
|
|
164
|
+
|
|
150
165
|
event: [],
|
|
151
166
|
error: [],
|
|
152
167
|
};
|
|
@@ -166,7 +181,7 @@ module.exports = (client) => class ChartSession {
|
|
|
166
181
|
}
|
|
167
182
|
|
|
168
183
|
constructor() {
|
|
169
|
-
this.#client.sessions[this.#
|
|
184
|
+
this.#client.sessions[this.#chartSessionID] = {
|
|
170
185
|
type: 'chart',
|
|
171
186
|
onData: (packet) => {
|
|
172
187
|
if (global.TW_DEBUG) console.log('§90§30§106 CHART SESSION §0 DATA', packet);
|
|
@@ -187,7 +202,10 @@ module.exports = (client) => class ChartSession {
|
|
|
187
202
|
}
|
|
188
203
|
|
|
189
204
|
if (['timescale_update', 'du'].includes(packet.type)) {
|
|
205
|
+
const changes = [];
|
|
206
|
+
|
|
190
207
|
Object.keys(packet.data[1]).forEach((k) => {
|
|
208
|
+
changes.push(k);
|
|
191
209
|
if (k === '$prices') {
|
|
192
210
|
const periods = packet.data[1].$prices;
|
|
193
211
|
if (!periods || !periods.s) return;
|
|
@@ -200,7 +218,7 @@ module.exports = (client) => class ChartSession {
|
|
|
200
218
|
close: p.v[4],
|
|
201
219
|
max: p.v[2],
|
|
202
220
|
min: p.v[3],
|
|
203
|
-
|
|
221
|
+
volume: Math.round(p.v[5] * 100) / 100,
|
|
204
222
|
};
|
|
205
223
|
});
|
|
206
224
|
|
|
@@ -210,7 +228,7 @@ module.exports = (client) => class ChartSession {
|
|
|
210
228
|
if (this.#studyListeners[k]) this.#studyListeners[k](packet);
|
|
211
229
|
});
|
|
212
230
|
|
|
213
|
-
this.#handleEvent('update');
|
|
231
|
+
this.#handleEvent('update', changes);
|
|
214
232
|
return;
|
|
215
233
|
}
|
|
216
234
|
|
|
@@ -231,7 +249,47 @@ module.exports = (client) => class ChartSession {
|
|
|
231
249
|
},
|
|
232
250
|
};
|
|
233
251
|
|
|
234
|
-
this.#client.
|
|
252
|
+
this.#client.sessions[this.#replaySessionID] = {
|
|
253
|
+
type: 'replay',
|
|
254
|
+
onData: (packet) => {
|
|
255
|
+
if (global.TW_DEBUG) console.log('§90§30§106 REPLAY SESSION §0 DATA', packet);
|
|
256
|
+
|
|
257
|
+
if (packet.type === 'replay_ok') {
|
|
258
|
+
if (this.#replayOKCB[packet.data[1]]) {
|
|
259
|
+
this.#replayOKCB[packet.data[1]]();
|
|
260
|
+
delete this.#replayOKCB[packet.data[1]];
|
|
261
|
+
}
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (packet.type === 'replay_instance_id') {
|
|
266
|
+
this.#handleEvent('replayLoaded', packet.data[1]);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (packet.type === 'replay_point') {
|
|
271
|
+
this.#handleEvent('replayPoint', packet.data[1]);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (packet.type === 'replay_resolutions') {
|
|
276
|
+
this.#handleEvent('replayResolution', packet.data[1], packet.data[2]);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (packet.type === 'replay_data_end') {
|
|
281
|
+
this.#handleEvent('replayEnd');
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (packet.type === 'critical_error') {
|
|
286
|
+
const [, name, description] = packet.data;
|
|
287
|
+
this.#handleError('Critical error:', name, description);
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
this.#client.send('chart_create_session', [this.#chartSessionID]);
|
|
235
293
|
}
|
|
236
294
|
|
|
237
295
|
#seriesCreated = false;
|
|
@@ -241,22 +299,25 @@ module.exports = (client) => class ChartSession {
|
|
|
241
299
|
/**
|
|
242
300
|
* @param {import('../types').TimeFrame} timeframe Chart period timeframe
|
|
243
301
|
* @param {number} [range] Number of loaded periods/candles (Default: 100)
|
|
302
|
+
* @param {number} [reference] Reference candle timestamp (Default is now)
|
|
244
303
|
*/
|
|
245
|
-
setSeries(timeframe = '240', range = 100) {
|
|
304
|
+
setSeries(timeframe = '240', range = 100, reference = null) {
|
|
246
305
|
if (!this.#currentSeries) {
|
|
247
306
|
this.#handleError('Please set the market before setting series');
|
|
248
307
|
return;
|
|
249
308
|
}
|
|
250
309
|
|
|
310
|
+
const calcRange = !reference ? range : ['bar_count', reference, range];
|
|
311
|
+
|
|
251
312
|
this.#periods = {};
|
|
252
313
|
|
|
253
314
|
this.#client.send(`${this.#seriesCreated ? 'modify' : 'create'}_series`, [
|
|
254
|
-
this.#
|
|
315
|
+
this.#chartSessionID,
|
|
255
316
|
'$prices',
|
|
256
317
|
's1',
|
|
257
318
|
`ser_${this.#currentSeries}`,
|
|
258
319
|
timeframe,
|
|
259
|
-
this.#seriesCreated ? '' :
|
|
320
|
+
this.#seriesCreated ? '' : calcRange,
|
|
260
321
|
]);
|
|
261
322
|
|
|
262
323
|
this.#seriesCreated = true;
|
|
@@ -268,41 +329,67 @@ module.exports = (client) => class ChartSession {
|
|
|
268
329
|
* @param {Object} [options] Chart options
|
|
269
330
|
* @param {import('../types').TimeFrame} [options.timeframe] Chart period timeframe
|
|
270
331
|
* @param {number} [options.range] Number of loaded periods/candles (Default: 100)
|
|
332
|
+
* @param {number} [options.to] Last candle timestamp (Default is now)
|
|
271
333
|
* @param {'splits' | 'dividends'} [options.adjustment] Market adjustment
|
|
272
334
|
* @param {'regular' | 'extended'} [options.session] Chart session
|
|
273
335
|
* @param {'EUR' | 'USD' | string} [options.currency] Chart currency
|
|
274
336
|
* @param {ChartType} [options.type] Chart custom type
|
|
275
337
|
* @param {ChartInputs} [options.inputs] Chart custom inputs
|
|
338
|
+
* @param {number} [options.replay] Replay mode starting point (Timestamp)
|
|
276
339
|
*/
|
|
277
340
|
setMarket(symbol, options = {}) {
|
|
278
341
|
this.#periods = {};
|
|
279
342
|
|
|
343
|
+
if (this.#replayMode) {
|
|
344
|
+
this.#replayMode = false;
|
|
345
|
+
this.#client.send('replay_delete_session', [this.#replaySessionID]);
|
|
346
|
+
}
|
|
347
|
+
|
|
280
348
|
const symbolInit = {
|
|
281
349
|
symbol: symbol || 'BTCEUR',
|
|
282
350
|
adjustment: options.adjustment || 'splits',
|
|
283
351
|
};
|
|
284
352
|
|
|
285
353
|
if (options.session) symbolInit.session = options.session;
|
|
286
|
-
|
|
287
354
|
if (options.currency) symbolInit['currency-id'] = options.currency;
|
|
288
355
|
|
|
289
|
-
|
|
356
|
+
if (options.replay) {
|
|
357
|
+
this.#replayMode = true;
|
|
358
|
+
this.#client.send('replay_create_session', [this.#replaySessionID]);
|
|
359
|
+
|
|
360
|
+
this.#client.send('replay_add_series', [
|
|
361
|
+
this.#replaySessionID,
|
|
362
|
+
'req_replay_addseries',
|
|
363
|
+
`=${JSON.stringify(symbolInit)}`,
|
|
364
|
+
options.timeframe,
|
|
365
|
+
]);
|
|
366
|
+
|
|
367
|
+
this.#client.send('replay_reset', [
|
|
368
|
+
this.#replaySessionID,
|
|
369
|
+
'req_replay_reset',
|
|
370
|
+
options.replay,
|
|
371
|
+
]);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const complex = options.type || options.replay;
|
|
375
|
+
const chartInit = complex ? {} : symbolInit;
|
|
290
376
|
|
|
291
|
-
if (
|
|
377
|
+
if (complex) {
|
|
378
|
+
if (options.replay) chartInit.replay = this.#replaySessionID;
|
|
292
379
|
chartInit.symbol = symbolInit;
|
|
293
380
|
chartInit.type = ChartTypes[options.type];
|
|
294
|
-
chartInit.inputs = { ...options.inputs };
|
|
381
|
+
if (options.type) chartInit.inputs = { ...options.inputs };
|
|
295
382
|
}
|
|
296
383
|
|
|
297
384
|
this.#currentSeries += 1;
|
|
298
385
|
|
|
299
386
|
this.#client.send('resolve_symbol', [
|
|
300
|
-
this.#
|
|
387
|
+
this.#chartSessionID,
|
|
301
388
|
`ser_${this.#currentSeries}`,
|
|
302
389
|
`=${JSON.stringify(chartInit)}`,
|
|
303
390
|
]);
|
|
304
391
|
|
|
305
|
-
this.setSeries(options.timeframe, options.range);
|
|
392
|
+
this.setSeries(options.timeframe, options.range, options.to);
|
|
306
393
|
}
|
|
307
394
|
|
|
308
395
|
/**
|
|
@@ -311,7 +398,7 @@ module.exports = (client) => class ChartSession {
|
|
|
311
398
|
*/
|
|
312
399
|
setTimezone(timezone) {
|
|
313
400
|
this.#periods = {};
|
|
314
|
-
this.#client.send('switch_timezone', [this.#
|
|
401
|
+
this.#client.send('switch_timezone', [this.#chartSessionID, timezone]);
|
|
315
402
|
}
|
|
316
403
|
|
|
317
404
|
/**
|
|
@@ -319,7 +406,60 @@ module.exports = (client) => class ChartSession {
|
|
|
319
406
|
* @param {number} number Number of additional periods/candles you want to fetch
|
|
320
407
|
*/
|
|
321
408
|
fetchMore(number = 1) {
|
|
322
|
-
this.#client.send('request_more_data', [this.#
|
|
409
|
+
this.#client.send('request_more_data', [this.#chartSessionID, '$prices', number]);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Fetch x additional previous periods/candles values
|
|
414
|
+
* @param {number} number Number of additional periods/candles you want to fetch
|
|
415
|
+
* @returns {Promise} Raise when the data has been fetched
|
|
416
|
+
*/
|
|
417
|
+
replayStep(number = 1) {
|
|
418
|
+
return new Promise((cb) => {
|
|
419
|
+
if (!this.#replayMode) {
|
|
420
|
+
this.#handleError('No replay session');
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const reqID = genSessionID('rsq_step');
|
|
425
|
+
this.#client.send('replay_step', [this.#replaySessionID, reqID, number]);
|
|
426
|
+
this.#replayOKCB[reqID] = () => { cb(); };
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Start fetching a new period/candle every x ms
|
|
432
|
+
* @param {number} interval Number of additional periods/candles you want to fetch
|
|
433
|
+
* @returns {Promise} Raise when the replay mode starts
|
|
434
|
+
*/
|
|
435
|
+
replayStart(interval = 1000) {
|
|
436
|
+
return new Promise((cb) => {
|
|
437
|
+
if (!this.#replayMode) {
|
|
438
|
+
this.#handleError('No replay session');
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const reqID = genSessionID('rsq_start');
|
|
443
|
+
this.#client.send('replay_start', [this.#replaySessionID, reqID, interval]);
|
|
444
|
+
this.#replayOKCB[reqID] = () => { cb(); };
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Stop fetching a new period/candle every x ms
|
|
450
|
+
* @returns {Promise} Raise when the replay mode stops
|
|
451
|
+
*/
|
|
452
|
+
replayStop() {
|
|
453
|
+
return new Promise((cb) => {
|
|
454
|
+
if (!this.#replayMode) {
|
|
455
|
+
this.#handleError('No replay session');
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const reqID = genSessionID('rsq_stop');
|
|
460
|
+
this.#client.send('replay_stop', [this.#replaySessionID, reqID]);
|
|
461
|
+
this.#replayOKCB[reqID] = () => { cb(); };
|
|
462
|
+
});
|
|
323
463
|
}
|
|
324
464
|
|
|
325
465
|
/**
|
|
@@ -333,13 +473,52 @@ module.exports = (client) => class ChartSession {
|
|
|
333
473
|
|
|
334
474
|
/**
|
|
335
475
|
* When a chart update happens
|
|
336
|
-
* @param {() => void} cb
|
|
476
|
+
* @param {(changes: ('$prices' | string)[]) => void} cb
|
|
337
477
|
* @event
|
|
338
478
|
*/
|
|
339
479
|
onUpdate(cb) {
|
|
340
480
|
this.#callbacks.update.push(cb);
|
|
341
481
|
}
|
|
342
482
|
|
|
483
|
+
/**
|
|
484
|
+
* When the replay session is ready
|
|
485
|
+
* @param {() => void} cb
|
|
486
|
+
* @event
|
|
487
|
+
*/
|
|
488
|
+
onReplayLoaded(cb) {
|
|
489
|
+
this.#callbacks.replayLoaded.push(cb);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* When the replay session has new resolution
|
|
494
|
+
* @param {(
|
|
495
|
+
* timeframe: import('../types').TimeFrame,
|
|
496
|
+
* index: number,
|
|
497
|
+
* ) => void} cb
|
|
498
|
+
* @event
|
|
499
|
+
*/
|
|
500
|
+
onReplayResolution(cb) {
|
|
501
|
+
this.#callbacks.replayResolution.push(cb);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* When the replay session ends
|
|
506
|
+
* @param {() => void} cb
|
|
507
|
+
* @event
|
|
508
|
+
*/
|
|
509
|
+
onReplayEnd(cb) {
|
|
510
|
+
this.#callbacks.replayEnd.push(cb);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* When the replay session cursor has moved
|
|
515
|
+
* @param {(index: number) => void} cb
|
|
516
|
+
* @event
|
|
517
|
+
*/
|
|
518
|
+
onReplayPoint(cb) {
|
|
519
|
+
this.#callbacks.replayPoint.push(cb);
|
|
520
|
+
}
|
|
521
|
+
|
|
343
522
|
/**
|
|
344
523
|
* When chart error happens
|
|
345
524
|
* @param {(...any) => void} cb Callback
|
|
@@ -351,7 +530,7 @@ module.exports = (client) => class ChartSession {
|
|
|
351
530
|
|
|
352
531
|
/** @type {ChartSessionBridge} */
|
|
353
532
|
#chartSession = {
|
|
354
|
-
sessionID: this.#
|
|
533
|
+
sessionID: this.#chartSessionID,
|
|
355
534
|
studyListeners: this.#studyListeners,
|
|
356
535
|
indexes: {},
|
|
357
536
|
send: (t, p) => this.#client.send(t, p),
|
|
@@ -361,7 +540,9 @@ module.exports = (client) => class ChartSession {
|
|
|
361
540
|
|
|
362
541
|
/** Delete the chart session */
|
|
363
542
|
delete() {
|
|
364
|
-
this.#client.send('
|
|
365
|
-
|
|
543
|
+
if (this.#replayMode) this.#client.send('replay_delete_session', [this.#replaySessionID]);
|
|
544
|
+
this.#client.send('chart_delete_session', [this.#chartSessionID]);
|
|
545
|
+
delete this.#client.sessions[this.#chartSessionID];
|
|
546
|
+
this.#replayMode = false;
|
|
366
547
|
}
|
|
367
548
|
};
|