@mathieuc/tradingview 3.5.2 → 4.0.0-beta.1
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/README.md +112 -51
- package/dist/chart/chart-session.d.ts +114 -0
- package/dist/chart/chart-session.js +339 -0
- package/dist/chart/graphics.d.ts +129 -0
- package/dist/chart/graphics.js +153 -0
- package/dist/chart/index.d.ts +11 -0
- package/dist/chart/index.js +6 -0
- package/dist/chart/strategy.d.ts +113 -0
- package/dist/chart/strategy.js +78 -0
- package/dist/chart/study.d.ts +60 -0
- package/dist/chart/study.js +179 -0
- package/dist/chart/timeframes.d.ts +7 -0
- package/dist/chart/timeframes.js +22 -0
- package/dist/chart/types.d.ts +105 -0
- package/dist/chart/types.js +9 -0
- package/dist/client/client.d.ts +89 -0
- package/dist/client/client.js +254 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +2 -0
- package/dist/client/transport.d.ts +27 -0
- package/dist/client/transport.js +38 -0
- package/dist/data/candles.d.ts +40 -0
- package/dist/data/candles.js +101 -0
- package/dist/data/history.d.ts +61 -0
- package/dist/data/history.js +101 -0
- package/dist/data/index.d.ts +30 -0
- package/dist/data/index.js +16 -0
- package/dist/data/indicators.d.ts +54 -0
- package/dist/data/indicators.js +139 -0
- package/dist/data/operation.d.ts +71 -0
- package/dist/data/operation.js +205 -0
- package/dist/data/provider.d.ts +23 -0
- package/dist/data/provider.js +11 -0
- package/dist/data/quotes.d.ts +33 -0
- package/dist/data/quotes.js +117 -0
- package/dist/data/symbols.d.ts +9 -0
- package/dist/data/symbols.js +19 -0
- package/dist/errors.d.ts +53 -0
- package/dist/errors.js +24 -0
- package/dist/events.d.ts +36 -0
- package/dist/events.js +70 -0
- package/dist/http/account.d.ts +47 -0
- package/dist/http/account.js +127 -0
- package/dist/http/index.d.ts +11 -0
- package/dist/http/index.js +5 -0
- package/dist/http/indicators.d.ts +37 -0
- package/dist/http/indicators.js +144 -0
- package/dist/http/layouts.d.ts +36 -0
- package/dist/http/layouts.js +24 -0
- package/dist/http/market.d.ts +45 -0
- package/dist/http/market.js +59 -0
- package/dist/http/pine-permissions.d.ts +29 -0
- package/dist/http/pine-permissions.js +56 -0
- package/dist/http/request.d.ts +44 -0
- package/dist/http/request.js +83 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +19 -0
- package/dist/indicators/builtin-indicator.d.ts +17 -0
- package/dist/indicators/builtin-indicator.js +75 -0
- package/dist/indicators/index.d.ts +8 -0
- package/dist/indicators/index.js +2 -0
- package/dist/indicators/pine-indicator.d.ts +63 -0
- package/dist/indicators/pine-indicator.js +101 -0
- package/dist/protocol/compression.d.ts +12 -0
- package/dist/protocol/compression.js +83 -0
- package/dist/protocol/framing.d.ts +59 -0
- package/dist/protocol/framing.js +68 -0
- package/dist/protocol/ids.d.ts +2 -0
- package/dist/protocol/ids.js +10 -0
- package/dist/protocol/index.d.ts +4 -0
- package/dist/protocol/index.js +3 -0
- package/dist/quote/fields.d.ts +35 -0
- package/dist/quote/fields.js +21 -0
- package/dist/quote/index.d.ts +4 -0
- package/dist/quote/index.js +2 -0
- package/dist/quote/quote-session.d.ts +73 -0
- package/dist/quote/quote-session.js +205 -0
- package/docs/README.es.md +58 -0
- package/docs/README.fr.md +58 -0
- package/docs/README.pt.md +58 -0
- package/docs/data-api.md +285 -0
- package/docs/low-level-api.md +213 -0
- package/docs/migration-v4.md +128 -0
- package/docs/release-4.0.0-beta.1.md +39 -0
- package/docs/v4-coverage.md +213 -0
- package/package.json +53 -20
- package/.env.sample +0 -2
- package/.eslintrc.js +0 -28
- package/.gitattributes +0 -2
- package/docs/DOCS.md +0 -3
- package/examples/AllPrivateIndicators.js +0 -44
- package/examples/BuiltInIndicator.js +0 -51
- package/examples/CustomChartType.js +0 -123
- package/examples/CustomTimeframe.js +0 -31
- package/examples/Errors.js +0 -155
- package/examples/FakeReplayMode.js +0 -40
- package/examples/FromToData.js +0 -35
- package/examples/GetDrawings.js +0 -27
- package/examples/GraphicIndicator.js +0 -42
- package/examples/MultipleSyncFetch.js +0 -44
- package/examples/PinePermManage.js +0 -67
- package/examples/ReplayMode.js +0 -103
- package/examples/Search.js +0 -14
- package/examples/SimpleChart.js +0 -63
- package/examples/UserLogin.js +0 -16
- package/main.js +0 -11
- package/src/chart/graphicParser.js +0 -308
- package/src/chart/session.js +0 -553
- package/src/chart/study.js +0 -435
- package/src/classes/BuiltInIndicator.js +0 -137
- package/src/classes/PineIndicator.js +0 -132
- package/src/classes/PinePermManager.js +0 -159
- package/src/client.js +0 -298
- package/src/miscRequests.js +0 -609
- package/src/protocol.js +0 -60
- package/src/quote/market.js +0 -132
- package/src/quote/session.js +0 -125
- package/src/types.js +0 -36
- package/src/utils.js +0 -20
- package/vite.config.js +0 -7
package/docs/data-api.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Data API guide
|
|
2
|
+
|
|
3
|
+
[README](../README.md) · [Low-level API](low-level-api.md) · [Migrating from v3](migration-v4.md) · [Examples](../examples)
|
|
4
|
+
|
|
5
|
+
**V4 beta is currently available from this repository only; the latest npm release is still v3.** Build this checkout before running the examples below.
|
|
6
|
+
|
|
7
|
+
The data API is the simplest way to use this library, in any application. Each function opens what it needs, waits for complete data, and releases every websocket session (and the connection it opened) before returning, including on errors, timeouts and cancellation.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { getCandles, watchQuotes } from '@mathieuc/tradingview/data';
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Everything here is also exported from the root entry (`@mathieuc/tradingview`).
|
|
14
|
+
|
|
15
|
+
| Function | Returns |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `getCandles(query)` | Candles, oldest first |
|
|
18
|
+
| `watchCandles(query, handlers)` | A watcher streaming candle snapshots |
|
|
19
|
+
| `getQuote(query)` / `getQuotes(query)` | Current quote(s) |
|
|
20
|
+
| `watchQuotes(query, handlers)` | A watcher streaming quotes |
|
|
21
|
+
| `getSymbolInfo(query)` | Symbol metadata (exchange, currency, session...) |
|
|
22
|
+
| `getIndicatorData(query)` | Indicator values, drawings and strategy report |
|
|
23
|
+
| `watchIndicator(query, handlers)` | A watcher streaming indicator results |
|
|
24
|
+
| `searchMarkets(text, options?)` | Markets matching a text |
|
|
25
|
+
| `searchIndicators(text, options?)` | Built-in and community indicators |
|
|
26
|
+
| `getTechnicalAnalysis(symbol, options?)` | TradingView technical ratings |
|
|
27
|
+
|
|
28
|
+
## Candles
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
const candles = await getCandles({ symbol: 'BINANCE:BTCUSDT', timeframe: '60', count: 500 });
|
|
32
|
+
const last = candles.at(-1); // { time, open, high, low, close, volume }
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`time` is the bar open time in Unix **seconds**. `getCandles('BINANCE:BTCUSDT')` is a shorthand for 100 daily candles.
|
|
36
|
+
|
|
37
|
+
| Option | Default | Description |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| `symbol` | required | Exchange-qualified symbol: `BINANCE:BTCUSDT`, `NASDAQ:AAPL`, `FX:EURUSD`... Use `searchMarkets` to find one. |
|
|
40
|
+
| `timeframe` | `'D'` | `1`, `5`, `15`, `60`, `240` (minutes), `D`, `W`, `M`, `1S` (seconds)... |
|
|
41
|
+
| `count` | `100` | Number of most recent bars. Larger counts are loaded in batches automatically (deep history). |
|
|
42
|
+
| `from` | | `Date` or Unix seconds. Loads every bar from this time (deep history); `count` is then ignored. |
|
|
43
|
+
| `to` | now | `Date` or Unix seconds: newest bar time. |
|
|
44
|
+
| `maxCount` | `20000` | Safety cap for `from` ranges. |
|
|
45
|
+
| `chartType` | | `HeikinAshi`, `Renko`, `LineBreak`, `Kagi`, `PointAndFigure` or `Range`. |
|
|
46
|
+
| `chartInputs` | | Inputs for `chartType`, e.g. `{ boxSize: 3, style: 'ATR', atrLength: 14 }`. |
|
|
47
|
+
| `currency` | | Convert prices, e.g. `EUR`. |
|
|
48
|
+
| `session` | | `regular` or `extended`. |
|
|
49
|
+
| `adjustment` | `'splits'` | `splits`, `dividends` or `none`. |
|
|
50
|
+
| `backAdjustment` | | Back-adjust continuous futures. |
|
|
51
|
+
| `timezone` | | Chart timezone (affects daily and longer bar alignment). |
|
|
52
|
+
| `credentials`, `client`, `clientOptions`, `timeoutMs`, `signal` | | See [Connections, timeouts and cancellation](#connections-timeouts-and-cancellation). |
|
|
53
|
+
|
|
54
|
+
History stops early, without error, when the server has no more bars (`series_completed` reports `data_completed: "end"` or `"limit"`). Anonymous access is limited: in our tests, about 7 000 one-minute bars, and reference times (`to`) in the past were capped. An empty result rejects with `NO_DATA`; when the server reported a limit, the message says so.
|
|
55
|
+
|
|
56
|
+
## Watching candles
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const watcher = await watchCandles({ symbol: 'BINANCE:BTCUSDT', timeframe: '1', count: 50 }, {
|
|
60
|
+
onData(candles) {
|
|
61
|
+
console.log(candles.at(-1)?.close);
|
|
62
|
+
},
|
|
63
|
+
onError(error) {
|
|
64
|
+
console.error(error.code, error.message);
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// ...later
|
|
69
|
+
await watcher.stop(); // Idempotent
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- The promise resolves once the initial history is loaded; `onData` has already received it.
|
|
73
|
+
- Each snapshot is a frozen array of the `count` most recent bars, oldest first.
|
|
74
|
+
- `watcher.latest` holds the last snapshot, `watcher.symbolInfo` the symbol metadata.
|
|
75
|
+
- `watcher.closed` resolves when the watcher stops: after `stop()`, an aborted `signal`, or a fatal error.
|
|
76
|
+
- Errors before start-up reject the promise. Afterwards they go to `onError`; fatal ones (disconnection, symbol or series errors) also stop the watcher. There is no automatic reconnection: start a new watcher when `closed` resolves if you need one.
|
|
77
|
+
|
|
78
|
+
`watchCandles` accepts the same chart options as `getCandles`, except `from`, `to` and `maxCount`.
|
|
79
|
+
|
|
80
|
+
## Quotes
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const quote = await getQuote('BINANCE:BTCUSDT');
|
|
84
|
+
console.log(quote.lp, quote.chp); // Last price, change in percent
|
|
85
|
+
|
|
86
|
+
const quotes = await getQuotes({ symbols: ['NASDAQ:AAPL', 'FX:EURUSD'], fields: 'price' });
|
|
87
|
+
console.log(quotes['NASDAQ:AAPL'].lp);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
| Option | Default | Description |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| `symbol` / `symbols` | required | One symbol, or a non-empty list (duplicates are ignored). |
|
|
93
|
+
| `fields` | `'all'` | `all`, `price` (`lp` only), or a list such as `['lp', 'bid', 'ask', 'volume']`. |
|
|
94
|
+
| `session` | `'regular'` | `regular` or `extended`. |
|
|
95
|
+
|
|
96
|
+
A quote contains the fields TradingView sent: `lp`, `lp_time`, `ch`, `chp`, `bid`, `ask`, `volume`, `open_price`, `high_price`, `low_price`, `prev_close_price`, `description`, `currency_code`... An unknown symbol rejects with `QUOTE_ERROR`.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const watcher = await watchQuotes({ symbols: ['BINANCE:BTCUSDT', 'BINANCE:ETHUSDT'] }, {
|
|
100
|
+
onData(symbol, quote, changes) {
|
|
101
|
+
console.log(symbol, quote.lp, changes);
|
|
102
|
+
},
|
|
103
|
+
onError: console.error,
|
|
104
|
+
});
|
|
105
|
+
console.log(watcher.latest); // Latest quote per symbol
|
|
106
|
+
await watcher.stop();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`watchQuotes` resolves once every symbol has loaded or failed. Failing symbols are reported to `onError` and the others keep streaming; if all fail, the promise rejects.
|
|
110
|
+
|
|
111
|
+
## Symbol information
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
const info = await getSymbolInfo('NASDAQ:AAPL');
|
|
115
|
+
console.log(info.description, info.currency_code, info.timezone, info.session, info.pricescale);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Anonymous sessions may be served by a substitute feed: for `NASDAQ:AAPL`, `full_name` can be `BATS:AAPL` while `pro_name` stays `NASDAQ:AAPL`.
|
|
119
|
+
|
|
120
|
+
## Indicators and strategies
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const rsi = await getIndicatorData({
|
|
124
|
+
symbol: 'BINANCE:BTCEUR',
|
|
125
|
+
timeframe: '60',
|
|
126
|
+
indicator: 'STD;RSI',
|
|
127
|
+
inputs: { Length: 21 },
|
|
128
|
+
credentials, // Pine scripts need an account
|
|
129
|
+
});
|
|
130
|
+
console.log(rsi.values.at(-1)); // { $time, RSI: 54.2, ... }
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`indicator` accepts:
|
|
134
|
+
|
|
135
|
+
- a script ID: `STD;RSI` (built-in Pine), `PUB;xxxx` (community), `USER;xxxx` (private); use `searchIndicators` to find IDs, and `version` to pin a version;
|
|
136
|
+
- a built-in study type: `Volume@tv-basicstudies-241`, `VbPFixed@tv-basicstudies-241!`... (works without an account);
|
|
137
|
+
- a `PineIndicator` or `BuiltInIndicator` instance (it is copied, never modified).
|
|
138
|
+
|
|
139
|
+
`inputs` sets Pine inputs (by input ID `in_0`, number, inline name or internal ID, with type and option validation) or built-in options.
|
|
140
|
+
|
|
141
|
+
The result contains:
|
|
142
|
+
|
|
143
|
+
| Field | Description |
|
|
144
|
+
| --- | --- |
|
|
145
|
+
| `indicator` | The indicator definition used. |
|
|
146
|
+
| `candles` | Chart bars, oldest first. |
|
|
147
|
+
| `values` | One row per bar: `$time` plus one key per plot (unnamed or duplicate plots are `plot_N`). The server may compute a few rows before the first returned candle. |
|
|
148
|
+
| `graphics` | Drawings: `labels`, `lines`, `boxes`, `tables` (with `cells`), `polygons`, `horizLines`, `horizHists`, and `raw`. X positions are bars back from the latest loaded bar. |
|
|
149
|
+
| `strategyReport` | For Pine strategies: `performance`, `trades` (most recent first), `history` (equity, drawdown, buy & hold), `currency`, `settings`. Empty for studies. |
|
|
150
|
+
|
|
151
|
+
Without an account, TradingView refuses Pine studies ("maximum number of studies per chart"): the call rejects with `STUDY_ERROR`. Built-in studies work.
|
|
152
|
+
|
|
153
|
+
`watchIndicator(query, { onData, onError })` streams the same result on every study update; `watcher.latest` holds the last one.
|
|
154
|
+
|
|
155
|
+
### Strategy totals and open positions
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { summarizeStrategyReport } from '@mathieuc/tradingview/data';
|
|
159
|
+
|
|
160
|
+
const summary = summarizeStrategyReport(result.strategyReport);
|
|
161
|
+
// tradeRecordCount, closedTradeCount, openTradeCount,
|
|
162
|
+
// closedNetProfit, openPnL, totalPnL, currency
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Trade records can include open positions with a current exit valuation. An `exit`
|
|
166
|
+
object does **not** establish that a trade is closed. The summary uses reported
|
|
167
|
+
`performance.all.totalTrades` and `totalOpenTrades`, never the record count, for
|
|
168
|
+
closed/open counts. It does not assign a closed/open status to individual records.
|
|
169
|
+
Counts may differ from the available records in a partial report.
|
|
170
|
+
|
|
171
|
+
`totalPnL` is closed net profit plus open PnL, in the report currency. Missing or
|
|
172
|
+
non-finite values remain `undefined`; a missing open PnL is not assumed to be zero.
|
|
173
|
+
Raw percentage/fraction fields are not rescaled. History series, including buy &
|
|
174
|
+
hold, are retained independently even when no equity series is provided. Updates
|
|
175
|
+
replace supplied arrays and retain omitted series; an empty array clears a series.
|
|
176
|
+
|
|
177
|
+
Malformed trade lists (a non-array or non-object records) raise `PARSE_ERROR`
|
|
178
|
+
before any part of that report is applied. Studies emit this error for both plain
|
|
179
|
+
and compressed reports. Omitted trade lists retain previous records; `[]` clears them.
|
|
180
|
+
This is structural validation, not full validation of every trade field.
|
|
181
|
+
|
|
182
|
+
These offline checks validate report decoding and normalization, not fresh-client
|
|
183
|
+
access, Replay playback, export entitlement or Deep Backtesting availability.
|
|
184
|
+
|
|
185
|
+
In a Basic-account UI check on October 3, 2026, both strategy trade CSV export and
|
|
186
|
+
strategy report XLSX export opened an upgrade prompt recommending Essential.
|
|
187
|
+
No successful export was verified. These are TradingView UI entitlements, not
|
|
188
|
+
library export methods or a guarantee about other accounts. Deep Backtesting is
|
|
189
|
+
separate and was blocked by a Premium upgrade prompt in that session.
|
|
190
|
+
|
|
191
|
+
### Complete strategy report example
|
|
192
|
+
|
|
193
|
+
See [strategy-report.js](../examples/strategy-report.js) for a bounded, executable
|
|
194
|
+
public-strategy → trade-records → PnL-summary workflow. Run it from a repository
|
|
195
|
+
checkout after building:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
node --env-file=.env examples/strategy-report.js
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
It uses the account cookies from `.env`, runs a public Supertrend strategy and
|
|
202
|
+
closes its connection automatically. It places no orders. Trade records are
|
|
203
|
+
most recent first and can include open positions with current exit valuations;
|
|
204
|
+
use the reported aggregate counts rather than inferring closure from an exit.
|
|
205
|
+
Missing summary fields remain `undefined`, not zero. `count` selects returned
|
|
206
|
+
candles, not a guaranteed exact strategy backtest window. Basic was sufficient
|
|
207
|
+
for the tested symbol/timeframe; UI exports and Deep Backtesting have separate
|
|
208
|
+
subscription requirements.
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
## Search and technical analysis
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
const markets = await searchMarkets('BINANCE:BTC', { type: 'crypto' });
|
|
215
|
+
// [{ id: 'BINANCE:BTCUSDT', exchange, fullExchange, symbol, description, type, currency, country }, ...]
|
|
216
|
+
|
|
217
|
+
const indicators = await searchIndicators('RSI');
|
|
218
|
+
// [{ id: 'STD;RSI', version, name, author, image, source, type, access }, ...]
|
|
219
|
+
|
|
220
|
+
const ratings = await getTechnicalAnalysis('BINANCE:BTCUSDT');
|
|
221
|
+
// { '1': { All, MA, Other }, '5': ..., '1D': ..., '1W': ..., '1M': ... } or null
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`searchMarkets` options: `type` (`stock`, `crypto`, `forex`, `futures`, `index`, `cfd`, `economic`...), `exchange`, `offset` (pagination). Ratings range from -2 (strong sell) to 2 (strong buy).
|
|
225
|
+
|
|
226
|
+
## Connections, timeouts and cancellation
|
|
227
|
+
|
|
228
|
+
Websocket data functions accept:
|
|
229
|
+
|
|
230
|
+
| Option | Description |
|
|
231
|
+
| --- | --- |
|
|
232
|
+
| `timeoutMs` | Default 15 000. One-shot functions: whole call. Watchers: until start-up. Rejects with `TIMEOUT`. Raise it for deep history. |
|
|
233
|
+
| `signal` | An `AbortSignal`. Aborting rejects with `ABORTED` (or stops a running watcher). |
|
|
234
|
+
| `credentials` | `{ session, signature }`: your `sessionid` and `sessionid_sign` cookies, for data your account can access. |
|
|
235
|
+
| `clientOptions` | Options for the connection opened by the call (`server`, `transport`, `debug`, `fetch`...). |
|
|
236
|
+
| `client` | Reuse an open `TradingViewClient`. The call only removes its own sessions and leaves the connection open. Useful for many calls in a row. |
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
import { TradingViewClient, getCandles, getQuote } from '@mathieuc/tradingview';
|
|
240
|
+
|
|
241
|
+
const client = new TradingViewClient({ credentials });
|
|
242
|
+
try {
|
|
243
|
+
const [candles, quote] = await Promise.all([
|
|
244
|
+
getCandles({ symbol: 'BINANCE:BTCUSDT', client }),
|
|
245
|
+
getQuote({ symbol: 'BINANCE:BTCUSDT', client }),
|
|
246
|
+
]);
|
|
247
|
+
} finally {
|
|
248
|
+
await client.close();
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Keep credentials in environment variables or a secret store; never put them in source files, issues or prompts.
|
|
253
|
+
|
|
254
|
+
## Alternate candle providers
|
|
255
|
+
|
|
256
|
+
The V4 data API remains usable with a source other than TradingView. Implement `MarketDataProvider.watchCandles(query, handlers)`; its worker exposes `latest` and an idempotent `stop()`. Pass the provider to `getCandles(query, provider)` for a one-shot snapshot or `watchCandles(query, handlers, provider)` for streaming. The provider controls its own network access and must resolve only after its first usable snapshot.
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
import { getCandles, type MarketDataProvider } from '@mathieuc/tradingview/data';
|
|
260
|
+
|
|
261
|
+
declare const myProvider: MarketDataProvider;
|
|
262
|
+
const candles = await getCandles({ symbol: 'CUSTOM:ASSET' }, myProvider);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`TradingViewProvider` implements the same contract and can carry default connection options. The regular `getCandles(query)` and `watchCandles(query, handlers)` calls use TradingView directly, so no provider setup is needed.
|
|
266
|
+
|
|
267
|
+
## Errors
|
|
268
|
+
|
|
269
|
+
Every failure is a `TradingViewError` with a `code`:
|
|
270
|
+
|
|
271
|
+
| Code | Meaning |
|
|
272
|
+
| --- | --- |
|
|
273
|
+
| `INVALID_ARGUMENT` | Invalid query (checked before connecting). |
|
|
274
|
+
| `SYMBOL_ERROR` | Unknown symbol. |
|
|
275
|
+
| `SERIES_ERROR` | Bars refused (for example a chart type or timeframe your account cannot use). |
|
|
276
|
+
| `CRITICAL_ERROR` | Command refused (invalid timeframe, timezone...). |
|
|
277
|
+
| `STUDY_ERROR` | Indicator failed or not allowed. |
|
|
278
|
+
| `QUOTE_ERROR` | Quote refused for a symbol. |
|
|
279
|
+
| `NO_DATA` | No bars in the requested range. |
|
|
280
|
+
| `AUTH_ERROR` | Credentials rejected. |
|
|
281
|
+
| `NOT_FOUND` | Unknown indicator, layout... |
|
|
282
|
+
| `TIMEOUT`, `ABORTED`, `DISCONNECTED`, `CONNECTION_ERROR`, `PROTOCOL_ERROR`, `HTTP_ERROR`, `PARSE_ERROR` | Transport and decoding failures. |
|
|
283
|
+
| `CALLBACK_ERROR` | A watcher callback threw; the stream remains active. |
|
|
284
|
+
|
|
285
|
+
`error.details` keeps the raw server payload when there is one.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Low-level API
|
|
2
|
+
|
|
3
|
+
[README](../README.md) · [Data API](data-api.md) · [Migrating from v3](migration-v4.md) · [Examples](../examples)
|
|
4
|
+
|
|
5
|
+
Use the low-level API when you need full control: several charts and studies on one connection, replay mode, raw protocol access, or long-lived sessions you manage yourself. The [data API](data-api.md) is built on it.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { TradingViewClient, BuiltInIndicator, getIndicator } from '@mathieuc/tradingview';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Events
|
|
12
|
+
|
|
13
|
+
Clients, charts, studies, quote sessions and quote subscriptions share one typed event API:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
const off = emitter.on('update', (changes) => {}); // Returns an unsubscribe function
|
|
17
|
+
emitter.once('symbolLoaded', (info) => {});
|
|
18
|
+
emitter.off('update', listener);
|
|
19
|
+
emitter.onAny((event, ...args) => {}); // Every event
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
An `error` event without any listener is written to `console.error`. A throwing listener never breaks the protocol state: its exception is re-thrown asynchronously.
|
|
23
|
+
|
|
24
|
+
## Client
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
const client = new TradingViewClient({
|
|
28
|
+
credentials: { session: process.env.SESSION, signature: process.env.SIGNATURE }, // Optional
|
|
29
|
+
});
|
|
30
|
+
await client.ready; // Optional: packets are queued until the connection is ready
|
|
31
|
+
// ...
|
|
32
|
+
await client.close();
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Option | Description |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `credentials` | `sessionid` / `sessionid_sign` cookies. The client loads the account (`getUser`) to get the websocket auth token. Without credentials, the session is anonymous. |
|
|
38
|
+
| `authToken` | Websocket auth token (`User.authToken`), to skip the account lookup. |
|
|
39
|
+
| `location` | Page used for the account lookup, e.g. `https://fr.tradingview.com/`. |
|
|
40
|
+
| `server` | `data` (default), `prodata` (paid accounts) or `widgetdata`. |
|
|
41
|
+
| `headers` | Extra websocket headers. |
|
|
42
|
+
| `debug` | `true` logs traffic with `console.log`; a function receives log arguments. |
|
|
43
|
+
| `transport` | Custom websocket transport (proxy, other library, tests). See [Transport](#transport). |
|
|
44
|
+
| `fetch` | Custom `fetch` for the account lookup. |
|
|
45
|
+
| `connectTimeoutMs` | Time allowed to open and authenticate. Default 20 000. |
|
|
46
|
+
|
|
47
|
+
| Member | Description |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `ready` | Promise resolved once the auth token is sent; rejects on credential, connection or timeout failure. |
|
|
50
|
+
| `isOpen`, `isAuthenticated`, `isClosed` | State. |
|
|
51
|
+
| `serverInfo` | Server greeting (`session_id`, `release`, `protocol`...). |
|
|
52
|
+
| `createChart()` | New `ChartSession`. |
|
|
53
|
+
| `createQuoteSession(options)` | New `QuoteSession`. |
|
|
54
|
+
| `send(method, params)` | Sends a raw packet (escape hatch for commands this library does not wrap). |
|
|
55
|
+
| `close()` | Closes the connection; resolves once closed. Sessions are released without errors. |
|
|
56
|
+
|
|
57
|
+
Events: `open`, `hello` (server greeting), `ready`, `heartbeat` (answered automatically), `packet` (packets addressed to no session), `close` (code, reason), `error`.
|
|
58
|
+
|
|
59
|
+
If the connection drops unexpectedly, every chart, study and quote subscription emits a `DISCONNECTED` error. The client does not reconnect automatically: create a new client.
|
|
60
|
+
|
|
61
|
+
## Charts
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const chart = client.createChart();
|
|
65
|
+
chart.on('symbolLoaded', (info) => console.log(info.description));
|
|
66
|
+
chart.on('update', (changes) => console.log(chart.lastCandle));
|
|
67
|
+
chart.on('error', (error) => console.error(error.code, error.message));
|
|
68
|
+
|
|
69
|
+
chart.setMarket('BINANCE:BTCEUR', { timeframe: '60', count: 300 });
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`setMarket(symbol, options)`:
|
|
73
|
+
|
|
74
|
+
| Option | Description |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `timeframe` | Default `D`. |
|
|
77
|
+
| `count` | Bars to load when the series is created (default 100). **Negative** values load bars *after* `to` instead of before it. |
|
|
78
|
+
| `to` | Reference time (Unix seconds) of the last bar. Sent as `['bar_count', to, count]`. |
|
|
79
|
+
| `adjustment`, `backAdjustment`, `session`, `currency` | As in the data API. |
|
|
80
|
+
| `type`, `inputs` | Custom chart type (`HeikinAshi`, `Renko`, `LineBreak`, `Kagi`, `PointAndFigure`, `Range`) and its inputs. |
|
|
81
|
+
| `replay` | Start replay mode at this Unix time. See [Replay](#replay). |
|
|
82
|
+
|
|
83
|
+
The first `setMarket` creates the series. Later calls (another symbol, type or replay) modify it and keep its bar count and studies: TradingView only accepts an empty range when modifying a series. Use `fetchMore` or a new chart to load a different amount.
|
|
84
|
+
|
|
85
|
+
| Member | Description |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `candles` | Loaded bars, oldest first: `{ time, open, high, low, close, volume }`. |
|
|
88
|
+
| `lastCandle` | Most recent bar. |
|
|
89
|
+
| `symbolInfo` | Symbol metadata from `symbol_resolved` (with `series_id`). |
|
|
90
|
+
| `timeframe`, `seriesId`, `isReplay`, `isDeleted`, `studies` | State. |
|
|
91
|
+
| `setTimeframe(timeframe)` | Changes the timeframe (keeps studies). Throws `INVALID_STATE` before `setMarket`. |
|
|
92
|
+
| `setTimezone(timezone)` | Changes the chart timezone. |
|
|
93
|
+
| `fetchMore(count)` | Loads older bars (negative: newer bars after a past `to`). |
|
|
94
|
+
| `createStudy(indicator)` | Adds a study. |
|
|
95
|
+
| `delete()` | Deletes the chart and its replay session. Idempotent. |
|
|
96
|
+
|
|
97
|
+
Events: `symbolLoaded` (info), `update` (list of changed keys: `$prices` and/or study IDs), `seriesLoading`, `seriesCompleted` (`{ status, dataCompleted, turnaround }`: `dataCompleted` is `end` or `limit` when no more history can be loaded), `error`, and the replay events.
|
|
98
|
+
|
|
99
|
+
### Replay
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
chart.setMarket('BINANCE:BTCEUR', { timeframe: 'D', replay: Math.round(Date.now() / 1000) - 86_400 * 7, count: 1 });
|
|
103
|
+
chart.on('replayEnd', () => console.log('Reached the present'));
|
|
104
|
+
|
|
105
|
+
await chart.replayStep(1); // One bar forward; resolves when the server confirms
|
|
106
|
+
await chart.replayStart(1000); // Play automatically, one bar per second
|
|
107
|
+
await chart.replayStop();
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Replay events: `replayLoaded` (instance ID), `replayPoint` (cursor time), `replayResolution` (resolutions reported by the server), `replayEnd`. Replay methods reject with `INVALID_STATE` outside replay mode, and pending requests reject when the chart is deleted or the market changes.
|
|
111
|
+
|
|
112
|
+
## Studies
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const rsi = await getIndicator('STD;RSI', { credentials });
|
|
116
|
+
rsi.setInput('Length', 21);
|
|
117
|
+
const study = chart.createStudy(rsi);
|
|
118
|
+
|
|
119
|
+
study.on('ready', () => console.log(study.values.at(-1)));
|
|
120
|
+
study.on('update', (changes) => {}); // 'plots', 'graphic', 'report.perf', 'report.trades'...
|
|
121
|
+
study.on('error', (error) => console.error(error.message));
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
| Member | Description |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `values` | Rows `{ $time, <plot>: number }`, oldest first. |
|
|
127
|
+
| `graphics` | Parsed drawings (labels, lines, boxes, tables, polygons, horizontal lines and histograms, `raw`). |
|
|
128
|
+
| `strategyReport` | Strategy `performance`, `trades`, `history`, `currency`, `settings` (decoded from plain or compressed payloads). |
|
|
129
|
+
| `indicator`, `isReady`, `isRemoved` | State. |
|
|
130
|
+
| `setIndicator(indicator)` | Replaces the indicator, e.g. after changing inputs. |
|
|
131
|
+
| `remove()` | Removes the study. Idempotent. |
|
|
132
|
+
|
|
133
|
+
Events: `loading`, `ready` (`study_completed`), `update`, `error`.
|
|
134
|
+
|
|
135
|
+
### Indicator definitions
|
|
136
|
+
|
|
137
|
+
- `getIndicator(id, { version, credentials })` returns a `PineIndicator` from `STD;...`, `PUB;...` or `USER;...` IDs.
|
|
138
|
+
- `PineIndicator`: `id`, `version`, `description`, `shortDescription`, `inputs`, `plots`, `script`, `type`; `setInput(key, value)`, `setInputs(values)`, `findInput(key)`, `setType('StrategyScript@tv-scripting-101!')`, `clone()`.
|
|
139
|
+
- `new BuiltInIndicator(type, options?)`: built-in studies such as `Volume@tv-basicstudies-241` and the volume profiles (`VbPFixed@...`, `VbPSessions@...`, `VbPVisible@...`). `setOption(key, value, force?)` validates names and types for known types unless `force` is true.
|
|
140
|
+
- `parseIndicatorDefinition(result, id, version)` builds a `PineIndicator` from a cached `pine-facade` response.
|
|
141
|
+
|
|
142
|
+
## Quotes
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
const quotes = client.createQuoteSession({ fields: ['lp', 'bid', 'ask'] }); // or 'all' / 'price'
|
|
146
|
+
const btc = quotes.subscribe('BINANCE:BTCEUR', { session: 'regular' });
|
|
147
|
+
btc.on('data', (quote, changes) => console.log(quote.lp, changes));
|
|
148
|
+
btc.on('loaded', () => {});
|
|
149
|
+
btc.on('error', (error) => {});
|
|
150
|
+
|
|
151
|
+
btc.close(); // Stops this subscription
|
|
152
|
+
quotes.setFields('all');
|
|
153
|
+
quotes.delete(); // Deletes the session and its subscriptions
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Subscriptions to the same symbol and session share one server subscription; the symbol is removed from the server when the last one closes. `btc.data` holds the merged latest values.
|
|
157
|
+
|
|
158
|
+
## HTTP functions
|
|
159
|
+
|
|
160
|
+
All accept `{ fetch?, signal?, headers? }`; functions that can use an account also accept `credentials`.
|
|
161
|
+
|
|
162
|
+
| Function | Description |
|
|
163
|
+
| --- | --- |
|
|
164
|
+
| `searchMarkets(text, { type, exchange, offset })` | Symbol search (v3 endpoint). |
|
|
165
|
+
| `getTechnicalAnalysis(symbol)` | Technical ratings for 1m to 1M periods, or `null`. |
|
|
166
|
+
| `searchIndicators(text)` | Built-in (cached in memory; `clearIndicatorCache()`) and community indicators. |
|
|
167
|
+
| `getIndicator(id, { version, credentials })` | Pine indicator definition. |
|
|
168
|
+
| `getPrivateIndicators(credentials)` | Your saved scripts. |
|
|
169
|
+
| `loginUser({ username, password, remember, userAgent })` | Signs in and returns the account with its cookies. Accounts with 2FA or captcha challenges are not supported. |
|
|
170
|
+
| `getUser(credentials, { location, maxRedirects })` | Account behind session cookies (follows regional redirects, stops loops). |
|
|
171
|
+
| `getChartToken(layoutId, { credentials, userId })` | Chart-storage token for a layout. |
|
|
172
|
+
| `getDrawings(layoutId, { symbol, chartId, credentials, userId })` | Drawings saved in a layout. |
|
|
173
|
+
| `new PinePermissionManager(pineId, { credentials })` | `getUsers(limit, order)`, `addUser(username, expiration?)`, `modifyExpiration(username, expiration?)`, `removeUser(username)` for invite-only scripts you own. |
|
|
174
|
+
|
|
175
|
+
## Transport
|
|
176
|
+
|
|
177
|
+
The default transport uses the [`ws`](https://github.com/websockets/ws) package, which works in Node and Bun. To use a proxy or another websocket implementation, pass `transport`:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import type { TransportFactory } from '@mathieuc/tradingview';
|
|
181
|
+
|
|
182
|
+
const transport: TransportFactory = ({ url, origin, headers }, handlers) => {
|
|
183
|
+
const socket = createMySocket(url, { origin, headers });
|
|
184
|
+
socket.onopen = () => handlers.onOpen();
|
|
185
|
+
socket.onmessage = (event) => handlers.onMessage(String(event.data));
|
|
186
|
+
socket.onclose = (event) => handlers.onClose(event.code, event.reason);
|
|
187
|
+
socket.onerror = (event) => handlers.onError(new Error(String(event)));
|
|
188
|
+
return {
|
|
189
|
+
get isOpen() { return socket.readyState === 1; },
|
|
190
|
+
send: (data) => socket.send(data),
|
|
191
|
+
close: () => socket.close(),
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const client = new TradingViewClient({ transport });
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The same mechanism lets tests run without network access (see `tests/helpers/fake-server.ts`).
|
|
199
|
+
|
|
200
|
+
## Protocol helpers
|
|
201
|
+
|
|
202
|
+
`protocol` exposes the wire format for debugging and custom tooling:
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
import { protocol } from '@mathieuc/tradingview';
|
|
206
|
+
|
|
207
|
+
protocol.encodePacket('set_auth_token', ['token']); // '~m~36~m~{"m":"set_auth_token","p":["token"]}'
|
|
208
|
+
protocol.decodeFrames(rawMessage); // [{ type: 'packet' | 'heartbeat' | 'data' | 'invalid', ... }]
|
|
209
|
+
protocol.decodeCompressed(base64); // Strategy report payloads (ZIP, zlib, raw deflate, gzip, JSON)
|
|
210
|
+
protocol.createSessionId('cs'); // 'cs_Ab12Cd34Ef56'
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Frames are `~m~<length>~m~<payload>`, where the length counts UTF-16 code units; heartbeats are `~h~<id>` and must be echoed (the client does it).
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Migrating from v3 to v4
|
|
2
|
+
|
|
3
|
+
[README](../README.md) · [Data API](data-api.md) · [Low-level API](low-level-api.md) · [Coverage matrix](v4-coverage.md)
|
|
4
|
+
|
|
5
|
+
Version 4 is a complete TypeScript rewrite with **no compatibility layer**. Every v3 capability is still available (see the [coverage matrix](v4-coverage.md)), under a more consistent API. This page shows how to translate v3 code.
|
|
6
|
+
|
|
7
|
+
## Package
|
|
8
|
+
|
|
9
|
+
| v3 | v4 |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| CommonJS: `const TradingView = require('@mathieuc/tradingview')` | ESM: `import { ... } from '@mathieuc/tradingview'`. On Node ≥ 20.19 or ≥ 22.12, `require()` of the ESM package also works. |
|
|
12
|
+
| `agent.js` preview (`fetchCandles`, `watchCandles`) | `@mathieuc/tradingview/data` (`getCandles`, `watchCandles`, quotes, indicators...) |
|
|
13
|
+
| Preview `MarketDataProvider` / `TradingViewProvider` | Provider-neutral candle injection remains: `getCandles(query, provider)`, `watchCandles(query, handlers, provider)` |
|
|
14
|
+
| Node ≥ 14, untyped JSDoc | Node ≥ 20 or Bun, bundled TypeScript declarations |
|
|
15
|
+
| `axios`, `jszip`, `ws` dependencies | `ws` only (HTTP uses the built-in `fetch`) |
|
|
16
|
+
|
|
17
|
+
## Simplest path: the data API
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
// v3
|
|
21
|
+
const client = new TradingView.Client();
|
|
22
|
+
const chart = new client.Session.Chart();
|
|
23
|
+
chart.setMarket('BINANCE:BTCEUR', { timeframe: 'D', range: 100 });
|
|
24
|
+
chart.onUpdate(() => { console.log(chart.periods); client.end(); });
|
|
25
|
+
|
|
26
|
+
// v4
|
|
27
|
+
import { getCandles } from '@mathieuc/tradingview/data';
|
|
28
|
+
const candles = await getCandles({ symbol: 'BINANCE:BTCEUR', timeframe: 'D', count: 100 });
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Client
|
|
32
|
+
|
|
33
|
+
| v3 | v4 |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| `new Client({ token, signature })` | `new TradingViewClient({ credentials: { session, signature } })` |
|
|
36
|
+
| `server`, `location`, `headers` options | Same names |
|
|
37
|
+
| `DEBUG: true` (sets a global flag) | `debug: true` or `debug: (...args) => {}` (per client) |
|
|
38
|
+
| (not available) | `authToken`, `transport`, `fetch`, `connectTimeoutMs`, `client.ready` |
|
|
39
|
+
| `client.onConnected(cb)` | `client.on('open', cb)` |
|
|
40
|
+
| `client.onDisconnected(cb)` | `client.on('close', cb)` |
|
|
41
|
+
| `client.onLogged(cb)` | `client.on('ready', cb)`; the server greeting is `client.on('hello', cb)` / `client.serverInfo` |
|
|
42
|
+
| `client.onPing(cb)` | `client.on('heartbeat', cb)` |
|
|
43
|
+
| `client.onData(cb)` | `client.on('packet', cb)` |
|
|
44
|
+
| `client.onError(cb)` (`(...messages)`) | `client.on('error', (error) => ...)` (`TradingViewError`) |
|
|
45
|
+
| `client.onEvent(cb)` | `client.onAny((event, ...args) => ...)` |
|
|
46
|
+
| `client.isLogged`, `client.isOpen` | `client.isAuthenticated`, `client.isOpen` (and `client.isClosed`) |
|
|
47
|
+
| `client.send(t, p)` / `client.sendQueue()` | `client.send(method, params)`; the queue is flushed automatically |
|
|
48
|
+
| `client.end()` | `await client.close()` (now resolves once actually closed) |
|
|
49
|
+
| `new client.Session.Chart()` | `client.createChart()` |
|
|
50
|
+
| `new client.Session.Quote(options)` | `client.createQuoteSession(options)` |
|
|
51
|
+
|
|
52
|
+
## Charts
|
|
53
|
+
|
|
54
|
+
| v3 | v4 |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| `chart.setMarket(symbol, { range, to, backadjustment, ... })` | `chart.setMarket(symbol, { count, to, backAdjustment, ... })` (`timeframe`, `adjustment`, `session`, `currency`, `type`, `inputs`, `replay` unchanged). The default timeframe is now `D` (v3: `240`). An empty symbol throws instead of loading `BTCEUR`. |
|
|
57
|
+
| `chart.setSeries(timeframe)` | `chart.setTimeframe(timeframe)` (throws `INVALID_STATE` before `setMarket` instead of emitting an error) |
|
|
58
|
+
| `chart.periods` (newest first; `max`/`min`; volume rounded to 2 decimals) | `chart.candles` (**oldest first**; `high`/`low`; raw volume) and `chart.lastCandle` |
|
|
59
|
+
| `chart.infos` | `chart.symbolInfo` |
|
|
60
|
+
| `chart.setTimezone(tz)` | Same (no longer clears loaded bars) |
|
|
61
|
+
| `chart.fetchMore(n)` | Same |
|
|
62
|
+
| `chart.replayStep/Start/Stop()` | Same; they now reject with `INVALID_STATE` outside replay mode instead of never resolving |
|
|
63
|
+
| `chart.onSymbolLoaded(cb)` | `chart.on('symbolLoaded', (info) => ...)` |
|
|
64
|
+
| `chart.onUpdate(cb)` | `chart.on('update', (changes) => ...)` |
|
|
65
|
+
| `chart.onReplayLoaded/Point/Resolution/End(cb)` | `chart.on('replayLoaded' / 'replayPoint' / 'replayResolution' / 'replayEnd', cb)` |
|
|
66
|
+
| `chart.onError(cb)` | `chart.on('error', (error) => ...)` |
|
|
67
|
+
| (not available) | `chart.on('seriesCompleted', ...)`, `chart.on('seriesLoading', ...)` |
|
|
68
|
+
| `new chart.Study(indicator)` | `chart.createStudy(indicator)` |
|
|
69
|
+
| `chart.delete()` | Same (idempotent) |
|
|
70
|
+
|
|
71
|
+
## Studies
|
|
72
|
+
|
|
73
|
+
| v3 | v4 |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| `study.periods` (newest first) | `study.values` (**oldest first**, still keyed by `$time` and plot names) |
|
|
76
|
+
| `study.graphic` | `study.graphics`; `tables[i].cells()` is now the `tables[i].cells` array; `raw()` is now the `raw` object |
|
|
77
|
+
| `study.strategyReport` | Same |
|
|
78
|
+
| `study.instance` | `study.indicator` |
|
|
79
|
+
| `study.setIndicator(indicator)`, `study.remove()` | Same |
|
|
80
|
+
| `study.onReady/onUpdate/onError(cb)` | `study.on('ready' / 'update' / 'error', cb)` (also `loading`) |
|
|
81
|
+
|
|
82
|
+
## Quotes
|
|
83
|
+
|
|
84
|
+
| v3 | v4 |
|
|
85
|
+
| --- | --- |
|
|
86
|
+
| `new client.Session.Quote({ fields: 'all' })` | `client.createQuoteSession({ fields: 'all' })` |
|
|
87
|
+
| `{ customFields: ['lp'] }` | `{ fields: ['lp'] }` |
|
|
88
|
+
| `new quoteSession.Market(symbol, session)` | `quoteSession.subscribe(symbol, { session })` |
|
|
89
|
+
| `market.onLoaded/onData/onError/onEvent(cb)` | `subscription.on('loaded' / 'data' / 'error', cb)` / `onAny(cb)`; `data` also receives the changed fields |
|
|
90
|
+
| `market.close()`, `quoteSession.delete()` | `subscription.close()`, `quoteSession.delete()` |
|
|
91
|
+
|
|
92
|
+
## Indicators
|
|
93
|
+
|
|
94
|
+
| v3 | v4 |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| `TradingView.getIndicator(id, version, session, signature)` | `getIndicator(id, { version, credentials })` |
|
|
97
|
+
| `indicator.pineId`, `indicator.pineVersion` | `indicator.id`, `indicator.version` |
|
|
98
|
+
| `indicator.setOption(key, value)` | `indicator.setInput(key, value)` (chainable; also `setInputs({...})`, `clone()`) |
|
|
99
|
+
| `indicator.setType(type)` | Same |
|
|
100
|
+
| `new BuiltInIndicator(type)` + `setOption(key, value, FORCE)` | Same, plus initial options: `new BuiltInIndicator(type, { first_bar_time })` |
|
|
101
|
+
|
|
102
|
+
## HTTP functions
|
|
103
|
+
|
|
104
|
+
| v3 | v4 |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `searchMarketV3(text, filter, offset)` | `searchMarkets(text, { type, offset, exchange })` |
|
|
107
|
+
| `searchMarket(text, filter)` (deprecated v1 endpoint) | `searchMarkets(text, { type })` |
|
|
108
|
+
| `result.getTA()` | `getTechnicalAnalysis(result.id)` |
|
|
109
|
+
| `getTA(symbol)` (returned `false` without data) | `getTechnicalAnalysis(symbol)` (returns `null`) |
|
|
110
|
+
| `searchIndicator(text)` + `result.get()` | `searchIndicators(text)` + `getIndicator(result.id, { version: result.version })` |
|
|
111
|
+
| `getPrivateIndicators(session, signature)` + `result.get()` | `getPrivateIndicators({ session, signature })` + `getIndicator(result.id, { version, credentials })` |
|
|
112
|
+
| `loginUser(username, password, remember, UA)` | `loginUser({ username, password, remember, userAgent })` |
|
|
113
|
+
| `getUser(session, signature, location)` | `getUser({ session, signature }, { location })` (`id` is now a number) |
|
|
114
|
+
| `getChartToken(layout, { id, session, signature })` | `getChartToken(layout, { userId, credentials: { session, signature } })` |
|
|
115
|
+
| `getDrawings(layout, symbol, { id, session, signature }, chartID)` | `getDrawings(layout, { symbol, chartId, userId, credentials })` |
|
|
116
|
+
| `new PinePermManager(session, signature, pineId)` | `new PinePermissionManager(pineId, { credentials: { session, signature } })` (same methods) |
|
|
117
|
+
|
|
118
|
+
## Errors
|
|
119
|
+
|
|
120
|
+
v3 passed lists of strings to `onError` callbacks, or printed them. v4 uses `TradingViewError` everywhere, with a `code` (`SYMBOL_ERROR`, `SERIES_ERROR`, `CRITICAL_ERROR`, `STUDY_ERROR`, `AUTH_ERROR`, `TIMEOUT`...), a readable `message` and the raw server payload in `details`. Study errors are formatted with their context, e.g. `Study error: Invalid value of the 'factor' argument (-1)...`.
|
|
121
|
+
|
|
122
|
+
## High-level data preview (formerly agent-api)
|
|
123
|
+
|
|
124
|
+
| Preview (`agent.js`) | v4 |
|
|
125
|
+
| --- | --- |
|
|
126
|
+
| `fetchCandles({ symbol, timeframe, limit, timeoutMs, signal })` | `getCandles({ symbol, timeframe, count, timeoutMs, signal })` |
|
|
127
|
+
| `watchCandles(query, { onData, onError })` → `{ latest, stop() }` | `watchCandles(query, { onData, onError })` → `{ latest, stop(), closed, isActive, symbolInfo }` |
|
|
128
|
+
| `TradingViewProvider` / `MarketDataProvider` injection | Provider injection remains: `getCandles(query, provider)` or `watchCandles(query, handlers, provider)`; `client` and `clientOptions.transport` also work for TradingView |
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# 4.0.0-beta.1 release candidate
|
|
2
|
+
|
|
3
|
+
Status: prepared for review; not published by this change.
|
|
4
|
+
Target npm dist-tag: **beta**. Keep **latest** on 3.5.2.
|
|
5
|
+
|
|
6
|
+
## Changes since beta.0
|
|
7
|
+
|
|
8
|
+
- Preserve buy-and-hold history even when a report has no equity history (#331).
|
|
9
|
+
- Export `summarizeStrategyReport`: separate record counts, closed/open trade
|
|
10
|
+
counts, closed net profit, open PnL and total PnL; retain unknown fields as
|
|
11
|
+
undefined (#331).
|
|
12
|
+
- Reject structurally malformed trade lists before modifying a report; report
|
|
13
|
+
parse errors consistently for plain and compressed envelopes (#332).
|
|
14
|
+
- Add a runnable public-strategy/report/PnL example, with bounded execution,
|
|
15
|
+
credential checks and explicit failure status.
|
|
16
|
+
- Document Basic Replay playback evidence and separate paid UI export and
|
|
17
|
+
Deep Backtesting limits from library report access.
|
|
18
|
+
|
|
19
|
+
## Validation
|
|
20
|
+
|
|
21
|
+
- Deterministic Node/Bun suites, typecheck, lint, build and packed-consumer smoke
|
|
22
|
+
checks are required before publication.
|
|
23
|
+
- Basic live probe: daily BINANCE:BTCEUR Replay load, three step acknowledgments,
|
|
24
|
+
automatic bar advancement, start and stop acknowledgments.
|
|
25
|
+
- Strategy example executed against Basic; report aggregates and history returned.
|
|
26
|
+
- Private compressed strategy capture validated in the preceding fixes.
|
|
27
|
+
- No claim of universal Replay entitlement, UI export success or Deep Backtesting.
|
|
28
|
+
|
|
29
|
+
## Publication gate
|
|
30
|
+
|
|
31
|
+
Publication requires the maintainer's explicit go-ahead. After approval, use the
|
|
32
|
+
reviewed commit with a clean checkout, rerun package checks, and publish the
|
|
33
|
+
inspected tarball using `npm publish <tarball> --tag beta`. Verify the resulting
|
|
34
|
+
version and dist-tags. Do not use the default `latest` tag. No tag, GitHub release,
|
|
35
|
+
or npm publication is created by preparing this candidate.
|
|
36
|
+
|
|
37
|
+
For v3 migration and breaking changes inherited from beta.0, see
|
|
38
|
+
[migration-v4.md](migration-v4.md). This candidate adds no new intended breaking
|
|
39
|
+
change relative to beta.0.
|