@mathieuc/tradingview 3.3.2 → 3.4.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/.gitattributes +2 -2
- package/README.md +66 -66
- package/examples/Errors.js +147 -147
- package/package.json +39 -39
- package/src/chart/study.js +69 -51
- package/src/client.js +1 -1
- package/src/quote/market.js +18 -9
- package/src/quote/session.js +8 -8
- package/src/request.js +37 -37
- package/test.js +8 -4
- package/tests/{1. Search.js → 01. Search.js } +0 -1
- package/tests/{2. QuoteSession.js → 02. QuoteSession.js } +0 -3
- package/tests/{3. SimpleChart.js → 03. SimpleChart.js } +0 -2
- package/tests/{4. Indicators.js → 04. Indicators.js } +0 -4
- package/tests/{5. BuiltInIndicator.js → 05. BuiltInIndicator.js } +0 -2
- package/tests/{6. FakeReplayMode.js → 06. FakeReplayMode.js } +1 -3
- package/tests/{7. ReplayMode.js → 07. ReplayMode.js } +0 -2
- package/tests/{8. CustomChartTypes.js → 08. CustomChartTypes.js } +0 -2
- package/tests/10. Authenticated.js +95 -0
- /package/tests/{9. AllErrors.js → 09. AllErrors.js} +0 -0
package/.gitattributes
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
# Auto detect text files and perform LF normalization
|
|
2
|
-
* text=auto
|
|
1
|
+
# Auto detect text files and perform LF normalization
|
|
2
|
+
* text=auto
|
package/README.md
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
# TradingView API [](https://GitHub.com/Mathieu2301/TradingView-API/stargazers/)
|
|
2
|
-
|
|
3
|
-
[](https://github.com/Mathieu2301/TradingView-API/actions/workflows/node.js.yml)
|
|
4
|
-
[](https://www.codefactor.io/repository/github/mathieu2301/tradingview-api/overview/main)
|
|
5
|
-
[](https://GitHub.com/Mathieu2301/TradingView-API/commit/)
|
|
6
|
-
[](https://npmjs.com/@mathieuc/tradingview)
|
|
7
|
-
[](https://npmjs.com/@mathieuc/tradingview)
|
|
8
|
-
[](https://npmjs.com/package/@mathieuc/tradingview)
|
|
9
|
-
|
|
10
|
-
Get realtime market prices and indicator values from Tradingview !
|
|
11
|
-
|
|
12
|
-
## Features
|
|
13
|
-
|
|
14
|
-
- [x] Premium features
|
|
15
|
-
- [x] Automatically backtest many strategies and try many settings in a very little time
|
|
16
|
-
- [x] Get drawings you made on your chart
|
|
17
|
-
- [x] Works with invite-only indicators
|
|
18
|
-
- [x] Unlimited simultaneous indicators
|
|
19
|
-
- [x] Realtime
|
|
20
|
-
- [x] Get TradingView's technical analysis
|
|
21
|
-
- [x] Replay mode + Fake Replay mode (for free plan)
|
|
22
|
-
- [x] Get values from a specific date range
|
|
23
|
-
- [ ] TradingView socket server emulation
|
|
24
|
-
- [ ] Interract with public chats
|
|
25
|
-
- [ ] Get Screener top values
|
|
26
|
-
- [ ] Get Hotlists
|
|
27
|
-
- [ ] Get Calendar
|
|
28
|
-
- IF YOU WANT A FEATURE, ASK ME !
|
|
29
|
-
|
|
30
|
-
## Possibilities
|
|
31
|
-
|
|
32
|
-
- Trading bot
|
|
33
|
-
- Discord alerts
|
|
34
|
-
- Hard backtest
|
|
35
|
-
- Machine Learning based indicator
|
|
36
|
-
- Free replay mode for all timeframes
|
|
37
|
-
|
|
38
|
-
___
|
|
39
|
-
|
|
40
|
-
## Installation
|
|
41
|
-
|
|
42
|
-
Stable version:
|
|
43
|
-
|
|
44
|
-
```ruby
|
|
45
|
-
npm i @mathieuc/tradingview
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Last version:
|
|
49
|
-
|
|
50
|
-
```ruby
|
|
51
|
-
npm i github:Mathieu2301/TradingView-API
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Examples
|
|
55
|
-
|
|
56
|
-
You can find all the examples and snippets in `./examples` folder.
|
|
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.
|
|
61
|
-
___
|
|
62
|
-
|
|
63
|
-
## Problems
|
|
64
|
-
|
|
65
|
-
If you have errors in console or unwanted behavior,
|
|
66
|
-
please create an issue [here](https://github.com/Mathieu2301/Tradingview-API/issues).
|
|
1
|
+
# TradingView API [](https://GitHub.com/Mathieu2301/TradingView-API/stargazers/)
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Mathieu2301/TradingView-API/actions/workflows/node.js.yml)
|
|
4
|
+
[](https://www.codefactor.io/repository/github/mathieu2301/tradingview-api/overview/main)
|
|
5
|
+
[](https://GitHub.com/Mathieu2301/TradingView-API/commit/)
|
|
6
|
+
[](https://npmjs.com/@mathieuc/tradingview)
|
|
7
|
+
[](https://npmjs.com/@mathieuc/tradingview)
|
|
8
|
+
[](https://npmjs.com/package/@mathieuc/tradingview)
|
|
9
|
+
|
|
10
|
+
Get realtime market prices and indicator values from Tradingview !
|
|
11
|
+
|
|
12
|
+
## Features
|
|
13
|
+
|
|
14
|
+
- [x] Premium features
|
|
15
|
+
- [x] Automatically backtest many strategies and try many settings in a very little time
|
|
16
|
+
- [x] Get drawings you made on your chart
|
|
17
|
+
- [x] Works with invite-only indicators
|
|
18
|
+
- [x] Unlimited simultaneous indicators
|
|
19
|
+
- [x] Realtime
|
|
20
|
+
- [x] Get TradingView's technical analysis
|
|
21
|
+
- [x] Replay mode + Fake Replay mode (for free plan)
|
|
22
|
+
- [x] Get values from a specific date range
|
|
23
|
+
- [ ] TradingView socket server emulation
|
|
24
|
+
- [ ] Interract with public chats
|
|
25
|
+
- [ ] Get Screener top values
|
|
26
|
+
- [ ] Get Hotlists
|
|
27
|
+
- [ ] Get Calendar
|
|
28
|
+
- IF YOU WANT A FEATURE, ASK ME !
|
|
29
|
+
|
|
30
|
+
## Possibilities
|
|
31
|
+
|
|
32
|
+
- Trading bot
|
|
33
|
+
- Discord alerts
|
|
34
|
+
- Hard backtest
|
|
35
|
+
- Machine Learning based indicator
|
|
36
|
+
- Free replay mode for all timeframes
|
|
37
|
+
|
|
38
|
+
___
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
Stable version:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
npm i @mathieuc/tradingview
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Last version:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
npm i github:Mathieu2301/TradingView-API
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Examples
|
|
55
|
+
|
|
56
|
+
You can find all the examples and snippets in `./examples` folder.
|
|
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.
|
|
61
|
+
___
|
|
62
|
+
|
|
63
|
+
## Problems
|
|
64
|
+
|
|
65
|
+
If you have errors in console or unwanted behavior,
|
|
66
|
+
please create an issue [here](https://github.com/Mathieu2301/Tradingview-API/issues).
|
package/examples/Errors.js
CHANGED
|
@@ -1,147 +1,147 @@
|
|
|
1
|
-
const TradingView = require('../main');
|
|
2
|
-
|
|
3
|
-
/*
|
|
4
|
-
This example tests many types of errors
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const client = new TradingView.Client(); // Creates a websocket client
|
|
8
|
-
|
|
9
|
-
const tests = [
|
|
10
|
-
(next) => { /* Testing "Credentials error" */
|
|
11
|
-
console.info('\nTesting "Credentials error" error:');
|
|
12
|
-
|
|
13
|
-
const client2 = new TradingView.Client({
|
|
14
|
-
token: 'FAKE_CREDENTIALS', // Set wrong credentials
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
client2.onError((...err) => {
|
|
18
|
-
console.error(' => Client error:', err);
|
|
19
|
-
client2.end();
|
|
20
|
-
next();
|
|
21
|
-
});
|
|
22
|
-
},
|
|
23
|
-
|
|
24
|
-
(next) => { /* Testing "Invalid symbol" */
|
|
25
|
-
console.info('\nTesting "Invalid symbol" error:');
|
|
26
|
-
|
|
27
|
-
const chart = new client.Session.Chart();
|
|
28
|
-
chart.onError((...err) => { // Listen for errors
|
|
29
|
-
console.error(' => Chart error:', err);
|
|
30
|
-
chart.delete();
|
|
31
|
-
next();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
chart.setMarket('XXXXX'); // Set a wrong market
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
(next) => { /* Testing "Invalid timezone" */
|
|
38
|
-
console.info('\nTesting "Invalid timezone" error:');
|
|
39
|
-
|
|
40
|
-
const chart = new client.Session.Chart();
|
|
41
|
-
chart.onError((...err) => { // Listen for errors
|
|
42
|
-
console.error(' => Chart error:', err);
|
|
43
|
-
next();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
chart.setMarket('BINANCE:BTCEUR'); // Set a market
|
|
47
|
-
chart.setTimezone('Nowhere/Nowhere'); // Set a fake timezone
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
(next) => { /* Testing "Custom timeframe" */
|
|
51
|
-
console.info('\nTesting "Custom timeframe" error:');
|
|
52
|
-
|
|
53
|
-
const chart = new client.Session.Chart();
|
|
54
|
-
chart.onError((...err) => { // Listen for errors
|
|
55
|
-
console.error(' => Chart error:', err);
|
|
56
|
-
chart.delete();
|
|
57
|
-
next();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
chart.setMarket('BINANCE:BTCEUR', { // Set a market
|
|
61
|
-
timeframe: '20', // Set a custom timeframe
|
|
62
|
-
/*
|
|
63
|
-
Timeframe '20' isn't available because we are
|
|
64
|
-
not logged in as a premium TradingView account
|
|
65
|
-
*/
|
|
66
|
-
});
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
(next) => { /* Testing "Invalid timeframe" */
|
|
70
|
-
console.info('\nTesting "Invalid timeframe" error:');
|
|
71
|
-
|
|
72
|
-
const chart = new client.Session.Chart();
|
|
73
|
-
chart.onError((...err) => { // Listen for errors
|
|
74
|
-
console.error(' => Chart error:', err);
|
|
75
|
-
next();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
chart.setMarket('BINANCE:BTCEUR', { // Set a market
|
|
79
|
-
timeframe: 'XX', // Set a wrong timeframe
|
|
80
|
-
});
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
(next) => { /* Testing "Study not auth" */
|
|
84
|
-
console.info('\nTesting "Study not auth" error:');
|
|
85
|
-
|
|
86
|
-
const chart = new client.Session.Chart();
|
|
87
|
-
chart.onError((...err) => { // Listen for errors
|
|
88
|
-
console.error(' => Chart error:', err);
|
|
89
|
-
next();
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
chart.setMarket('BINANCE:BTCEUR', { // Set a market
|
|
93
|
-
timeframe: '15',
|
|
94
|
-
type: 'Renko',
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
chart.onUpdate(() => {
|
|
98
|
-
console.log('DATA', chart.periods[0]);
|
|
99
|
-
});
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
(next) => { /* Testing "Set the market before" */
|
|
103
|
-
console.info('\nTesting "Set the market before..." error:');
|
|
104
|
-
|
|
105
|
-
const chart = new client.Session.Chart();
|
|
106
|
-
chart.onError((...err) => { // Listen for errors
|
|
107
|
-
console.error(' => Chart error:', err);
|
|
108
|
-
chart.delete();
|
|
109
|
-
next();
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
chart.setSeries('15'); // Set series before setting the market
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
(next) => { /* Testing "Inexistent indicator" */
|
|
116
|
-
console.info('\nTesting "Inexistent indicator" error:');
|
|
117
|
-
|
|
118
|
-
TradingView.getIndicator('STD;XXXXXXX')
|
|
119
|
-
.catch((err) => {
|
|
120
|
-
console.error(' => API error:', [err.message]);
|
|
121
|
-
next();
|
|
122
|
-
});
|
|
123
|
-
},
|
|
124
|
-
|
|
125
|
-
async (next) => { /* Testing "Invalid value" */
|
|
126
|
-
console.info('\nTesting "Invalid value" error:');
|
|
127
|
-
|
|
128
|
-
const chart = new client.Session.Chart();
|
|
129
|
-
chart.setMarket('BINANCE:BTCEUR'); // Set a market
|
|
130
|
-
|
|
131
|
-
const ST = await TradingView.getIndicator('STD;Supertrend');
|
|
132
|
-
ST.setOption('Factor', -1); // This will cause an error
|
|
133
|
-
|
|
134
|
-
const Supertrend = new chart.Study(ST);
|
|
135
|
-
Supertrend.onError((...err) => {
|
|
136
|
-
console.error(' => Study error:', err);
|
|
137
|
-
chart.delete();
|
|
138
|
-
next();
|
|
139
|
-
});
|
|
140
|
-
},
|
|
141
|
-
];
|
|
142
|
-
|
|
143
|
-
(async () => {
|
|
144
|
-
// eslint-disable-next-line no-restricted-syntax, no-await-in-loop
|
|
145
|
-
for (const t of tests) await new Promise(t);
|
|
146
|
-
console.log(`\nTests ${tests.length}/${tests.length} done !`);
|
|
147
|
-
})();
|
|
1
|
+
const TradingView = require('../main');
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
This example tests many types of errors
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const client = new TradingView.Client(); // Creates a websocket client
|
|
8
|
+
|
|
9
|
+
const tests = [
|
|
10
|
+
(next) => { /* Testing "Credentials error" */
|
|
11
|
+
console.info('\nTesting "Credentials error" error:');
|
|
12
|
+
|
|
13
|
+
const client2 = new TradingView.Client({
|
|
14
|
+
token: 'FAKE_CREDENTIALS', // Set wrong credentials
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
client2.onError((...err) => {
|
|
18
|
+
console.error(' => Client error:', err);
|
|
19
|
+
client2.end();
|
|
20
|
+
next();
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
(next) => { /* Testing "Invalid symbol" */
|
|
25
|
+
console.info('\nTesting "Invalid symbol" error:');
|
|
26
|
+
|
|
27
|
+
const chart = new client.Session.Chart();
|
|
28
|
+
chart.onError((...err) => { // Listen for errors
|
|
29
|
+
console.error(' => Chart error:', err);
|
|
30
|
+
chart.delete();
|
|
31
|
+
next();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
chart.setMarket('XXXXX'); // Set a wrong market
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
(next) => { /* Testing "Invalid timezone" */
|
|
38
|
+
console.info('\nTesting "Invalid timezone" error:');
|
|
39
|
+
|
|
40
|
+
const chart = new client.Session.Chart();
|
|
41
|
+
chart.onError((...err) => { // Listen for errors
|
|
42
|
+
console.error(' => Chart error:', err);
|
|
43
|
+
next();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
chart.setMarket('BINANCE:BTCEUR'); // Set a market
|
|
47
|
+
chart.setTimezone('Nowhere/Nowhere'); // Set a fake timezone
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
(next) => { /* Testing "Custom timeframe" */
|
|
51
|
+
console.info('\nTesting "Custom timeframe" error:');
|
|
52
|
+
|
|
53
|
+
const chart = new client.Session.Chart();
|
|
54
|
+
chart.onError((...err) => { // Listen for errors
|
|
55
|
+
console.error(' => Chart error:', err);
|
|
56
|
+
chart.delete();
|
|
57
|
+
next();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
chart.setMarket('BINANCE:BTCEUR', { // Set a market
|
|
61
|
+
timeframe: '20', // Set a custom timeframe
|
|
62
|
+
/*
|
|
63
|
+
Timeframe '20' isn't available because we are
|
|
64
|
+
not logged in as a premium TradingView account
|
|
65
|
+
*/
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
(next) => { /* Testing "Invalid timeframe" */
|
|
70
|
+
console.info('\nTesting "Invalid timeframe" error:');
|
|
71
|
+
|
|
72
|
+
const chart = new client.Session.Chart();
|
|
73
|
+
chart.onError((...err) => { // Listen for errors
|
|
74
|
+
console.error(' => Chart error:', err);
|
|
75
|
+
next();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
chart.setMarket('BINANCE:BTCEUR', { // Set a market
|
|
79
|
+
timeframe: 'XX', // Set a wrong timeframe
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
(next) => { /* Testing "Study not auth" */
|
|
84
|
+
console.info('\nTesting "Study not auth" error:');
|
|
85
|
+
|
|
86
|
+
const chart = new client.Session.Chart();
|
|
87
|
+
chart.onError((...err) => { // Listen for errors
|
|
88
|
+
console.error(' => Chart error:', err);
|
|
89
|
+
next();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
chart.setMarket('BINANCE:BTCEUR', { // Set a market
|
|
93
|
+
timeframe: '15',
|
|
94
|
+
type: 'Renko',
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
chart.onUpdate(() => {
|
|
98
|
+
console.log('DATA', chart.periods[0]);
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
(next) => { /* Testing "Set the market before" */
|
|
103
|
+
console.info('\nTesting "Set the market before..." error:');
|
|
104
|
+
|
|
105
|
+
const chart = new client.Session.Chart();
|
|
106
|
+
chart.onError((...err) => { // Listen for errors
|
|
107
|
+
console.error(' => Chart error:', err);
|
|
108
|
+
chart.delete();
|
|
109
|
+
next();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
chart.setSeries('15'); // Set series before setting the market
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
(next) => { /* Testing "Inexistent indicator" */
|
|
116
|
+
console.info('\nTesting "Inexistent indicator" error:');
|
|
117
|
+
|
|
118
|
+
TradingView.getIndicator('STD;XXXXXXX')
|
|
119
|
+
.catch((err) => {
|
|
120
|
+
console.error(' => API error:', [err.message]);
|
|
121
|
+
next();
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
async (next) => { /* Testing "Invalid value" */
|
|
126
|
+
console.info('\nTesting "Invalid value" error:');
|
|
127
|
+
|
|
128
|
+
const chart = new client.Session.Chart();
|
|
129
|
+
chart.setMarket('BINANCE:BTCEUR'); // Set a market
|
|
130
|
+
|
|
131
|
+
const ST = await TradingView.getIndicator('STD;Supertrend');
|
|
132
|
+
ST.setOption('Factor', -1); // This will cause an error
|
|
133
|
+
|
|
134
|
+
const Supertrend = new chart.Study(ST);
|
|
135
|
+
Supertrend.onError((...err) => {
|
|
136
|
+
console.error(' => Study error:', err);
|
|
137
|
+
chart.delete();
|
|
138
|
+
next();
|
|
139
|
+
});
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
(async () => {
|
|
144
|
+
// eslint-disable-next-line no-restricted-syntax, no-await-in-loop
|
|
145
|
+
for (const t of tests) await new Promise(t);
|
|
146
|
+
console.log(`\nTests ${tests.length}/${tests.length} done !`);
|
|
147
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@mathieuc/tradingview",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Tradingview instant stocks API, indicator alerts, trading bot, and more !",
|
|
5
|
-
"main": "main.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "node test"
|
|
8
|
-
},
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/Mathieu2301/TradingView-API.git"
|
|
12
|
-
},
|
|
13
|
-
"engines": {
|
|
14
|
-
"node": ">=14.0.0"
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"tradingwiew",
|
|
18
|
-
"market",
|
|
19
|
-
"stocks",
|
|
20
|
-
"crypto",
|
|
21
|
-
"forex",
|
|
22
|
-
"indicator",
|
|
23
|
-
"bitcoin",
|
|
24
|
-
"api"
|
|
25
|
-
],
|
|
26
|
-
"author": "Mathieu Colmon",
|
|
27
|
-
"license": "ISC",
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"jszip": "^3.7.1",
|
|
30
|
-
"ws": "^7.4.3"
|
|
31
|
-
},
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"@babel/eslint-parser": "^7.15.7",
|
|
34
|
-
"@mathieuc/console": "^1.0.1",
|
|
35
|
-
"eslint": "^7.25.0",
|
|
36
|
-
"eslint-config-airbnb-base": "^14.2.1",
|
|
37
|
-
"eslint-plugin-import": "^2.22.1"
|
|
38
|
-
}
|
|
39
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@mathieuc/tradingview",
|
|
3
|
+
"version": "3.4.0",
|
|
4
|
+
"description": "Tradingview instant stocks API, indicator alerts, trading bot, and more !",
|
|
5
|
+
"main": "main.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node test"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/Mathieu2301/TradingView-API.git"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=14.0.0"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"tradingwiew",
|
|
18
|
+
"market",
|
|
19
|
+
"stocks",
|
|
20
|
+
"crypto",
|
|
21
|
+
"forex",
|
|
22
|
+
"indicator",
|
|
23
|
+
"bitcoin",
|
|
24
|
+
"api"
|
|
25
|
+
],
|
|
26
|
+
"author": "Mathieu Colmon",
|
|
27
|
+
"license": "ISC",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"jszip": "^3.7.1",
|
|
30
|
+
"ws": "^7.4.3"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@babel/eslint-parser": "^7.15.7",
|
|
34
|
+
"@mathieuc/console": "^1.0.1",
|
|
35
|
+
"eslint": "^7.25.0",
|
|
36
|
+
"eslint-config-airbnb-base": "^14.2.1",
|
|
37
|
+
"eslint-plugin-import": "^2.22.1"
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/chart/study.js
CHANGED
|
@@ -32,6 +32,27 @@ function getInputs(options) {
|
|
|
32
32
|
return options.options;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
const parseTrades = (trades) => trades.reverse().map((t) => ({
|
|
36
|
+
entry: {
|
|
37
|
+
name: t.e.c,
|
|
38
|
+
type: (t.e.tp[0] === 's' ? 'short' : 'long'),
|
|
39
|
+
value: t.e.p,
|
|
40
|
+
time: t.e.tm,
|
|
41
|
+
},
|
|
42
|
+
exit: {
|
|
43
|
+
name: t.x.c,
|
|
44
|
+
value: t.x.p,
|
|
45
|
+
time: t.x.tm,
|
|
46
|
+
},
|
|
47
|
+
quantity: t.q,
|
|
48
|
+
profit: t.tp,
|
|
49
|
+
cumulative: t.cp,
|
|
50
|
+
runup: t.rn,
|
|
51
|
+
drawdown: t.dd,
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
// const historyParser = (history) => history.reverse().map((h) => ({
|
|
55
|
+
|
|
35
56
|
/**
|
|
36
57
|
* @typedef {Object} TradeReport Trade report
|
|
37
58
|
|
|
@@ -86,9 +107,19 @@ function getInputs(options) {
|
|
|
86
107
|
* @prop {number} totalTrades Total trades
|
|
87
108
|
*/
|
|
88
109
|
|
|
110
|
+
/**
|
|
111
|
+
* @typedef {Object} FromTo
|
|
112
|
+
* @prop {number} from From timestamp
|
|
113
|
+
* @prop {number} to To timestamp
|
|
114
|
+
*/
|
|
115
|
+
|
|
89
116
|
/**
|
|
90
117
|
* @typedef {Object} StrategyReport
|
|
91
118
|
* @prop {'EUR' | 'USD' | 'JPY' | '' | 'CHF'} [currency] Selected currency
|
|
119
|
+
* @prop {Object} [settings] Backtester settings
|
|
120
|
+
* @prop {Object} [settings.dateRange] Backtester date range
|
|
121
|
+
* @prop {FromTo} [settings.dateRange.backtest] Date range for backtest
|
|
122
|
+
* @prop {FromTo} [settings.dateRange.trade] Date range for trade
|
|
92
123
|
* @prop {TradeReport[]} trades Trade list starting by the last
|
|
93
124
|
* @prop {Object} history History Chart value
|
|
94
125
|
* @prop {number[]} [history.buyHold] Buy hold values
|
|
@@ -275,60 +306,45 @@ module.exports = (chartSession) => class ChartStudy {
|
|
|
275
306
|
changes.push('graphic');
|
|
276
307
|
}
|
|
277
308
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
309
|
+
const updateStrategyReport = (report) => {
|
|
310
|
+
if (report.currency) {
|
|
311
|
+
this.#strategyReport.currency = report.currency;
|
|
312
|
+
changes.push('report.currency');
|
|
313
|
+
}
|
|
282
314
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
315
|
+
if (report.settings) {
|
|
316
|
+
this.#strategyReport.settings = report.settings;
|
|
317
|
+
changes.push('report.settings');
|
|
318
|
+
}
|
|
287
319
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
320
|
+
if (report.performance) {
|
|
321
|
+
this.#strategyReport.performance = report.performance;
|
|
322
|
+
changes.push('report.perf');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (report.trades) {
|
|
326
|
+
this.#strategyReport.trades = parseTrades(report.trades);
|
|
327
|
+
changes.push('report.trades');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (report.equity) {
|
|
331
|
+
this.#strategyReport.history = {
|
|
332
|
+
buyHold: report.buyHold,
|
|
333
|
+
buyHoldPercent: report.buyHoldPercent,
|
|
334
|
+
drawDown: report.drawDown,
|
|
335
|
+
drawDownPercent: report.drawDownPercent,
|
|
336
|
+
equity: report.equity,
|
|
337
|
+
equityPercent: report.equityPercent,
|
|
338
|
+
};
|
|
339
|
+
changes.push('report.history');
|
|
340
|
+
}
|
|
341
|
+
};
|
|
292
342
|
|
|
293
343
|
if (parsed.dataCompressed) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
this.#strategyReport = {
|
|
297
|
-
currency: parsedC.report.currency,
|
|
298
|
-
|
|
299
|
-
trades: parsedC.report.trades.reverse().map((t) => ({
|
|
300
|
-
entry: {
|
|
301
|
-
name: t.e.c,
|
|
302
|
-
type: (t.e.tp[0] === 's' ? 'short' : 'long'),
|
|
303
|
-
value: t.e.p,
|
|
304
|
-
time: t.e.tm,
|
|
305
|
-
},
|
|
306
|
-
exit: {
|
|
307
|
-
name: t.x.c,
|
|
308
|
-
value: t.x.p,
|
|
309
|
-
time: t.x.tm,
|
|
310
|
-
},
|
|
311
|
-
quantity: t.q,
|
|
312
|
-
profit: t.tp,
|
|
313
|
-
cumulative: t.cp,
|
|
314
|
-
runup: t.rn,
|
|
315
|
-
drawdown: t.dd,
|
|
316
|
-
})),
|
|
317
|
-
|
|
318
|
-
history: {
|
|
319
|
-
buyHold: parsedC.report.buyHold,
|
|
320
|
-
buyHoldPercent: parsedC.report.buyHoldPercent,
|
|
321
|
-
drawDown: parsedC.report.drawDown,
|
|
322
|
-
drawDownPercent: parsedC.report.drawDownPercent,
|
|
323
|
-
equity: parsedC.report.equity,
|
|
324
|
-
equityPercent: parsedC.report.equityPercent,
|
|
325
|
-
},
|
|
326
|
-
|
|
327
|
-
performance: parsedC.report.performance,
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
changes.push('fullReport');
|
|
344
|
+
updateStrategyReport((await parseCompressed(parsed.dataCompressed)).report);
|
|
331
345
|
}
|
|
346
|
+
|
|
347
|
+
if (parsed.data && parsed.data.report) updateStrategyReport(parsed.data.report);
|
|
332
348
|
}
|
|
333
349
|
|
|
334
350
|
if (data.ns.indexes && typeof data.ns.indexes === 'object') {
|
|
@@ -383,8 +399,10 @@ module.exports = (chartSession) => class ChartStudy {
|
|
|
383
399
|
}
|
|
384
400
|
|
|
385
401
|
/**
|
|
386
|
-
* @typedef {
|
|
387
|
-
*
|
|
402
|
+
* @typedef {'plots' | 'report.currency'
|
|
403
|
+
* | 'report.settings' | 'report.perf'
|
|
404
|
+
* | 'report.trades' | 'report.history'
|
|
405
|
+
* | 'graphic'
|
|
388
406
|
* } UpdateChangeType
|
|
389
407
|
*/
|
|
390
408
|
|
package/src/client.js
CHANGED
|
@@ -225,7 +225,7 @@ module.exports = class Client {
|
|
|
225
225
|
if (clientOptions.DEBUG) global.TW_DEBUG = clientOptions.DEBUG;
|
|
226
226
|
|
|
227
227
|
const server = clientOptions.server || 'data';
|
|
228
|
-
this.#ws = new WebSocket(`wss://${server}.tradingview.com/socket.io/websocket`, {
|
|
228
|
+
this.#ws = new WebSocket(`wss://${server}.tradingview.com/socket.io/websocket?&type=chart`, {
|
|
229
229
|
origin: 'https://s.tradingview.com',
|
|
230
230
|
});
|
|
231
231
|
|
package/src/quote/market.js
CHANGED
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @param {import('./session').QuoteSessionBridge} quoteSession
|
|
7
7
|
*/
|
|
8
|
+
|
|
8
9
|
module.exports = (quoteSession) => class QuoteMarket {
|
|
9
10
|
#symbolListeners = quoteSession.symbolListeners;
|
|
10
11
|
|
|
11
12
|
#symbol;
|
|
12
13
|
|
|
14
|
+
#session;
|
|
15
|
+
|
|
16
|
+
#symbolKey;
|
|
17
|
+
|
|
13
18
|
#symbolListenerID = 0;
|
|
14
19
|
|
|
15
20
|
#lastData = {};
|
|
@@ -38,20 +43,24 @@ module.exports = (quoteSession) => class QuoteMarket {
|
|
|
38
43
|
|
|
39
44
|
/**
|
|
40
45
|
* @param {string} symbol Market symbol (like: 'BTCEUR' or 'KRAKEN:BTCEUR')
|
|
46
|
+
* @param {string} session Market session (like: 'regular' or 'extended')
|
|
41
47
|
*/
|
|
42
|
-
constructor(symbol) {
|
|
48
|
+
constructor(symbol, session = 'regular') {
|
|
43
49
|
this.#symbol = symbol;
|
|
50
|
+
this.#session = session;
|
|
51
|
+
this.#symbolKey = `=${JSON.stringify({ session, symbol })}`;
|
|
44
52
|
|
|
45
|
-
if (!this.#symbolListeners[
|
|
46
|
-
this.#symbolListeners[
|
|
53
|
+
if (!this.#symbolListeners[this.#symbolKey]) {
|
|
54
|
+
this.#symbolListeners[this.#symbolKey] = [];
|
|
47
55
|
quoteSession.send('quote_add_symbols', [
|
|
48
56
|
quoteSession.sessionID,
|
|
49
|
-
|
|
57
|
+
this.#symbolKey,
|
|
50
58
|
]);
|
|
51
59
|
}
|
|
52
|
-
this.#symbolListenerID = this.#symbolListeners[symbol].length;
|
|
53
60
|
|
|
54
|
-
this.#symbolListeners[
|
|
61
|
+
this.#symbolListenerID = this.#symbolListeners[this.#symbolKey].length;
|
|
62
|
+
|
|
63
|
+
this.#symbolListeners[this.#symbolKey][this.#symbolListenerID] = (packet) => {
|
|
55
64
|
if (global.TW_DEBUG) console.log('§90§30§105 MARKET §0 DATA', packet);
|
|
56
65
|
|
|
57
66
|
if (packet.type === 'qsd' && packet.data[1].s === 'ok') {
|
|
@@ -112,12 +121,12 @@ module.exports = (quoteSession) => class QuoteMarket {
|
|
|
112
121
|
|
|
113
122
|
/** Close this listener */
|
|
114
123
|
close() {
|
|
115
|
-
if (this.#symbolListeners[this.#
|
|
124
|
+
if (this.#symbolListeners[this.#symbolKey].length <= 1) {
|
|
116
125
|
quoteSession.send('quote_remove_symbols', [
|
|
117
126
|
quoteSession.sessionID,
|
|
118
|
-
this.#
|
|
127
|
+
this.#symbolKey,
|
|
119
128
|
]);
|
|
120
129
|
}
|
|
121
|
-
delete this.#symbolListeners[this.#
|
|
130
|
+
delete this.#symbolListeners[this.#symbolKey][this.#symbolListenerID];
|
|
122
131
|
}
|
|
123
132
|
};
|
package/src/quote/session.js
CHANGED
|
@@ -79,21 +79,21 @@ module.exports = (client) => class QuoteSession {
|
|
|
79
79
|
if (global.TW_DEBUG) console.log('§90§30§102 QUOTE SESSION §0 DATA', packet);
|
|
80
80
|
|
|
81
81
|
if (packet.type === 'quote_completed') {
|
|
82
|
-
const
|
|
83
|
-
if (!this.#symbolListeners[
|
|
84
|
-
this.#client.send('quote_remove_symbols', [this.#sessionID,
|
|
82
|
+
const symbolKey = packet.data[1];
|
|
83
|
+
if (!this.#symbolListeners[symbolKey]) {
|
|
84
|
+
this.#client.send('quote_remove_symbols', [this.#sessionID, symbolKey]);
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
|
-
this.#symbolListeners[
|
|
87
|
+
this.#symbolListeners[symbolKey].forEach((h) => h(packet));
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
if (packet.type === 'qsd') {
|
|
91
|
-
const
|
|
92
|
-
if (!this.#symbolListeners[
|
|
93
|
-
this.#client.send('quote_remove_symbols', [this.#sessionID,
|
|
91
|
+
const symbolKey = packet.data[1].n;
|
|
92
|
+
if (!this.#symbolListeners[symbolKey]) {
|
|
93
|
+
this.#client.send('quote_remove_symbols', [this.#sessionID, symbolKey]);
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
|
-
this.#symbolListeners[
|
|
96
|
+
this.#symbolListeners[symbolKey].forEach((h) => h(packet));
|
|
97
97
|
}
|
|
98
98
|
},
|
|
99
99
|
};
|
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<{ 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;
|
|
1
|
+
const https = require('https');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {https.RequestOptions} options HTTPS Request options
|
|
5
|
+
* @param {boolean} [raw] Get raw or JSON data
|
|
6
|
+
* @param {string} [content] Request body content
|
|
7
|
+
* @returns {Promise<{ data: (string | object | array), cookies: string[] }>} Result
|
|
8
|
+
*/
|
|
9
|
+
function request(options = {}, raw = false, content = '') {
|
|
10
|
+
return new Promise((cb, err) => {
|
|
11
|
+
const req = https.request(options, (res) => {
|
|
12
|
+
let data = '';
|
|
13
|
+
res.on('data', (c) => { data += c; });
|
|
14
|
+
res.on('end', () => {
|
|
15
|
+
if (raw) {
|
|
16
|
+
cb({ data, cookies: res.headers['set-cookie'] });
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
data = JSON.parse(data);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.log(data);
|
|
24
|
+
err(new Error('Can\'t parse server response'));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
cb({ data, cookies: res.headers['set-cookie'] });
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
req.on('error', err);
|
|
33
|
+
req.end(content);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = request;
|
package/test.js
CHANGED
|
@@ -47,17 +47,21 @@ function success() {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
console.info('§90§30§104 ==== ALL TESTS DONE ==== §0\n');
|
|
50
|
+
|
|
51
|
+
let errored = false;
|
|
52
|
+
|
|
50
53
|
Object.keys(TESTS).forEach((t) => {
|
|
51
54
|
let color = '2';
|
|
52
55
|
if (TESTS[t].warnings) color = '3';
|
|
53
|
-
if (TESTS[t].errors)
|
|
56
|
+
if (TESTS[t].errors) {
|
|
57
|
+
color = '1';
|
|
58
|
+
errored = true;
|
|
59
|
+
}
|
|
54
60
|
|
|
55
61
|
console.info(`§90§30§10${color} ${t} §0 §91E§0: ${TESTS[t].errors}§0 §93W§0: ${TESTS[t].warnings}`);
|
|
56
|
-
// console.info(` - §91 Errors:§0 ${TESTS[t].errors}`);
|
|
57
|
-
// console.info(` - §93 Warnings:§0 ${TESTS[t].warnings}`);
|
|
58
62
|
});
|
|
59
63
|
|
|
60
|
-
process.exit(0);
|
|
64
|
+
process.exit(errored ? 1 : 0);
|
|
61
65
|
})();
|
|
62
66
|
|
|
63
67
|
setTimeout(() => {
|
|
@@ -5,7 +5,6 @@ module.exports = (log, success, warn, err, cb) => {
|
|
|
5
5
|
|
|
6
6
|
client.onError((...error) => {
|
|
7
7
|
err('Client error', ...error);
|
|
8
|
-
throw new Error('Client error');
|
|
9
8
|
});
|
|
10
9
|
|
|
11
10
|
const quoteSession = new client.Session.Quote({
|
|
@@ -38,7 +37,6 @@ module.exports = (log, success, warn, err, cb) => {
|
|
|
38
37
|
keys.forEach((k) => {
|
|
39
38
|
if (!rsKeys.includes(k)) {
|
|
40
39
|
err(`Missing '${k}' key in`, rsKeys);
|
|
41
|
-
throw new Error('Missing key');
|
|
42
40
|
}
|
|
43
41
|
});
|
|
44
42
|
|
|
@@ -49,6 +47,5 @@ module.exports = (log, success, warn, err, cb) => {
|
|
|
49
47
|
|
|
50
48
|
BTC.onError((...error) => {
|
|
51
49
|
err('BTCEUR ERROR:', error);
|
|
52
|
-
throw new Error('Missing key');
|
|
53
50
|
});
|
|
54
51
|
};
|
|
@@ -5,7 +5,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
5
5
|
|
|
6
6
|
client.onError((...error) => {
|
|
7
7
|
err('Client error', error);
|
|
8
|
-
throw new Error('Client error');
|
|
9
8
|
});
|
|
10
9
|
|
|
11
10
|
const chart = new client.Session.Chart();
|
|
@@ -16,7 +15,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
16
15
|
|
|
17
16
|
chart.onError((...error) => {
|
|
18
17
|
err('Chart error', error);
|
|
19
|
-
throw new Error('Chart error');
|
|
20
18
|
});
|
|
21
19
|
|
|
22
20
|
chart.onSymbolLoaded(() => { // When the symbol is successfully loaded
|
|
@@ -5,7 +5,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
5
5
|
|
|
6
6
|
client.onError((...error) => {
|
|
7
7
|
err('Client error', error);
|
|
8
|
-
throw new Error('Client error');
|
|
9
8
|
});
|
|
10
9
|
|
|
11
10
|
const chart = new client.Session.Chart();
|
|
@@ -15,7 +14,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
15
14
|
|
|
16
15
|
chart.onError((...error) => {
|
|
17
16
|
err('Chart error', error);
|
|
18
|
-
throw new Error('Chart error');
|
|
19
17
|
});
|
|
20
18
|
|
|
21
19
|
TradingView.getIndicator('STD;Supertrend%Strategy').then((indicator) => {
|
|
@@ -31,7 +29,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
31
29
|
|
|
32
30
|
SuperTrend.onError((...error) => {
|
|
33
31
|
err('SuperTrend error', error[0]);
|
|
34
|
-
throw new Error('SuperTrend error');
|
|
35
32
|
});
|
|
36
33
|
|
|
37
34
|
let QTY = 10;
|
|
@@ -81,7 +78,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
81
78
|
|
|
82
79
|
CipherB.onError((...error) => {
|
|
83
80
|
err('MarketCipher B error:', error[0]);
|
|
84
|
-
throw new Error('MarketCipher B error');
|
|
85
81
|
});
|
|
86
82
|
|
|
87
83
|
CipherB.onUpdate(() => {
|
|
@@ -5,7 +5,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
5
5
|
|
|
6
6
|
client.onError((...error) => {
|
|
7
7
|
err('Client error', error);
|
|
8
|
-
throw new Error('Client error');
|
|
9
8
|
});
|
|
10
9
|
|
|
11
10
|
const chart = new client.Session.Chart();
|
|
@@ -15,7 +14,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
15
14
|
|
|
16
15
|
chart.onError((...error) => {
|
|
17
16
|
err('Chart error', error);
|
|
18
|
-
throw new Error('Chart error');
|
|
19
17
|
});
|
|
20
18
|
|
|
21
19
|
const volumeProfile = new TradingView.BuiltInIndicator('VbPFixed@tv-basicstudies-139!');
|
|
@@ -5,7 +5,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
5
5
|
|
|
6
6
|
client.onError((...error) => {
|
|
7
7
|
err('Client error', error);
|
|
8
|
-
throw new Error('Client error');
|
|
9
8
|
});
|
|
10
9
|
|
|
11
10
|
const chart = new client.Session.Chart();
|
|
@@ -17,7 +16,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
17
16
|
|
|
18
17
|
chart.onError((...error) => {
|
|
19
18
|
err('Chart error', error);
|
|
20
|
-
throw new Error('Chart error');
|
|
21
19
|
});
|
|
22
20
|
|
|
23
21
|
let interval = NaN;
|
|
@@ -43,7 +41,7 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
43
41
|
if (Number.isNaN(interval) && times.length >= 2) interval = intrval;
|
|
44
42
|
|
|
45
43
|
if (!Number.isNaN(interval) && interval !== intrval) {
|
|
46
|
-
|
|
44
|
+
err(`Wrong interval: ${intrval} (should be ${interval})`);
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
log('Next ->', times[0]);
|
|
@@ -5,7 +5,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
5
5
|
|
|
6
6
|
client.onError((...error) => {
|
|
7
7
|
err('Client error', error);
|
|
8
|
-
throw new Error('Client error');
|
|
9
8
|
});
|
|
10
9
|
|
|
11
10
|
const chart = new client.Session.Chart();
|
|
@@ -17,7 +16,6 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
17
16
|
|
|
18
17
|
chart.onError((...error) => {
|
|
19
18
|
err('Chart error', error);
|
|
20
|
-
throw new Error('Chart error');
|
|
21
19
|
});
|
|
22
20
|
|
|
23
21
|
let finished = false;
|
|
@@ -5,14 +5,12 @@ module.exports = async (log, success, warn, err, cb) => {
|
|
|
5
5
|
|
|
6
6
|
client.onError((...error) => {
|
|
7
7
|
err('Client error', error);
|
|
8
|
-
throw new Error('Client error');
|
|
9
8
|
});
|
|
10
9
|
|
|
11
10
|
const chart = new client.Session.Chart();
|
|
12
11
|
|
|
13
12
|
chart.onError((...error) => {
|
|
14
13
|
err('Chart error', error);
|
|
15
|
-
throw new Error('Chart error');
|
|
16
14
|
});
|
|
17
15
|
|
|
18
16
|
/* (0s) Heikin Ashi chart */
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/* eslint-disable no-restricted-syntax */
|
|
2
|
+
/* eslint-disable no-await-in-loop */
|
|
3
|
+
const TradingView = require('../main');
|
|
4
|
+
|
|
5
|
+
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
6
|
+
|
|
7
|
+
module.exports = async (log, success, warn, err, cb) => {
|
|
8
|
+
log('Getting user info');
|
|
9
|
+
|
|
10
|
+
const userInfos = await TradingView.getUser(process.env.SESSION);
|
|
11
|
+
if (userInfos && userInfos.id) {
|
|
12
|
+
success('User info:', {
|
|
13
|
+
id: userInfos.id,
|
|
14
|
+
username: userInfos.username,
|
|
15
|
+
firstName: userInfos.firstName,
|
|
16
|
+
lastName: userInfos.lastName,
|
|
17
|
+
following: userInfos.following,
|
|
18
|
+
followers: userInfos.followers,
|
|
19
|
+
notifications: userInfos.notifications,
|
|
20
|
+
joinDate: userInfos.joinDate,
|
|
21
|
+
});
|
|
22
|
+
} else err('Get user error. Result:', userInfos);
|
|
23
|
+
|
|
24
|
+
await wait(1000);
|
|
25
|
+
|
|
26
|
+
log('Getting user indicators');
|
|
27
|
+
|
|
28
|
+
const userIndicators = await TradingView.getPrivateIndicators(process.env.SESSION);
|
|
29
|
+
if (userIndicators) {
|
|
30
|
+
if (userIndicators.length === 0) warn('No private indicator found');
|
|
31
|
+
else success('User indicators:', userIndicators.map((i) => i.name));
|
|
32
|
+
} else err('Get indicators error. Result:', userIndicators);
|
|
33
|
+
|
|
34
|
+
await wait(1000);
|
|
35
|
+
|
|
36
|
+
log('Creating logged client');
|
|
37
|
+
const client = new TradingView.Client({
|
|
38
|
+
token: process.env.SESSION,
|
|
39
|
+
});
|
|
40
|
+
client.onError((...error) => {
|
|
41
|
+
err('Client error', error);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const chart = new client.Session.Chart();
|
|
45
|
+
chart.onError((...error) => {
|
|
46
|
+
err('Chart error', error);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
log('Setting market to BINANCE:BTCEUR...');
|
|
50
|
+
chart.setMarket('BINANCE:BTCEUR', { timeframe: 'D' });
|
|
51
|
+
|
|
52
|
+
const checked = new Set();
|
|
53
|
+
async function check(item) {
|
|
54
|
+
checked.add(item);
|
|
55
|
+
log('Checked:', [...checked], `(${checked.size}/${userIndicators.length + 1})`);
|
|
56
|
+
if (checked.size < userIndicators.length + 1) return;
|
|
57
|
+
|
|
58
|
+
log('Closing client...');
|
|
59
|
+
chart.delete();
|
|
60
|
+
await client.end();
|
|
61
|
+
success('Client closed');
|
|
62
|
+
cb();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
chart.onUpdate(async () => {
|
|
66
|
+
success('Market data:', {
|
|
67
|
+
name: chart.infos.pro_name,
|
|
68
|
+
description: chart.infos.short_description,
|
|
69
|
+
exchange: chart.infos.exchange,
|
|
70
|
+
price: chart.periods[0].close,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await check(Symbol.for('PRICE'));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await wait(1000);
|
|
77
|
+
|
|
78
|
+
log('Loading indicators...');
|
|
79
|
+
|
|
80
|
+
for (const indic of userIndicators) {
|
|
81
|
+
const privateIndic = await indic.get();
|
|
82
|
+
log(`[${indic.name}] Loading indicator...`);
|
|
83
|
+
|
|
84
|
+
const indicator = new chart.Study(privateIndic);
|
|
85
|
+
|
|
86
|
+
indicator.onReady(() => {
|
|
87
|
+
success(`[${indic.name}] Indicator loaded !`);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
indicator.onUpdate(async () => {
|
|
91
|
+
success(`[${indic.name}] Last plot:`, indicator.periods[0]);
|
|
92
|
+
await check(indic.id);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
};
|
|
File without changes
|