opencli-plugin-tradingview
Read-only opencli adapter for the TradingView desktop macOS app. Exposes spot quotes, full options chains (with greeks/IV), expiries, screener (stocks/crypto/forex/futures/bonds), news, alerts, watchlists, symbol search, chart state, and chart screenshots — all by attaching to a logged-in TradingView.app over Chrome DevTools Protocol. No API key.
This plugin lives inside the himself65/finance-skills monorepo. Install it via opencli's monorepo subpath syntax:
opencli plugin install github:himself65/finance-skills/tradingview
Install + launch
# Prereqs: Node ≥ 24 (see engines.node), TradingView.app installed + logged in
npm install -g @jackwener/opencli
opencli plugin install github:himself65/finance-skills/tradingview
# Relaunch TradingView with --remote-debugging-port (one-time per session)
opencli tradingview launch
launch quits any running TradingView and reopens it with --remote-debugging-port=9222. Save chart layouts first.
Zero extra setup. No apps.yaml registration, no Browser Bridge extension. The plugin attaches to CDP directly via Node's built-in WebSocket.
Commands
Setup / chart inspection
| Command | Description | Output columns |
|---|---|---|
tradingview launch |
Relaunch TradingView with CDP port enabled | port, pid, ready |
tradingview status |
CDP connection state + active TradingView tabs | connected, tabs |
tradingview chart-state |
Active chart's symbol/interval/layout | layout_id, symbol, interval, url |
tradingview screenshot --output path.png |
PNG of an active chart tab | path, bytes |
Quotes + options
| Command | Description | Output columns |
|---|---|---|
tradingview quote --ticker X |
Single-symbol spot quote | symbol, close, change, change_abs, currency, time |
tradingview options-chain --ticker X |
Options chain (full or ATM band) | expiry, dte, strike, type, bid, ask, mid, iv, delta, gamma, theta, vega, rho, theo, bid_iv, ask_iv, symbol |
tradingview options-expiries --ticker X |
List available expiries | expiry, dte, contracts_count |
options-chain flags: --exchange (default NASDAQ), --expiry YYYY-MM-DD, --type call|put, --strikes-around-spot N (default 6, 0 = full strike list).
Screener + search
| Command | Description | Output columns |
|---|---|---|
tradingview screener --market <m> --columns <csv> |
Generic screener (stocks per country, crypto, forex, futures, bonds) | symbol + dynamic from --columns |
tradingview search --query <text> |
Symbol search / autocomplete | symbol, description, type, exchange, country, currency |
screener flags: --market (default america; supports ~70 country codes + crypto/coin/forex/futures/bond/global/options), --columns (CSV; append |TF for indicator timeframe like RSI|60), --filter (JSON array of {left, operation, right} clauses), --sort field:asc|desc (default volume:desc), --tickers (CSV of EXCH:SYM), --label-product (default screener-stock), --limit (1-500, default 50), --offset.
News + watchlists + alerts
| Command | Description | Output columns |
|---|---|---|
tradingview news |
News headlines (filterable) or full story by --id |
List: id, published, provider, title, urgency, related_symbols, link. Story: adds body, tags |
tradingview watchlists |
List all watchlists (or one via --id, or colored list via --color) |
id, name, symbol_count, symbols |
tradingview alerts --type <kind> |
Read-only alerts: list / active / triggered / offline / log | id, name, symbol, type, condition, value, active, status, fired_at |
news flags: --id, --symbol, --category {base|stock|etf|futures|forex|crypto|index|bond|economic}, --area {WLD|AME|EUR|ASI|OCN|AFR}, --section, --provider, --lang, --limit.
watchlists flags: --id <8-char> (one specific list), --color {red|orange|yellow|green|blue|purple} (colored-flag list).
alerts flags: --type {list|active|triggered|offline|log} (default list).
All commands accept -f json|yaml|md|csv|table.
Data path
The plugin replicates what TradingView's desktop app does internally — its main Electron process makes HTTP requests via Node's network stack, bypassing browser CORS. The plugin does the same:
- Connect to the running app's CDP (
http://127.0.0.1:9222/json/version) - Open the browser-level WebSocket
- Call
Storage.getCookiesto harvest the user's.tradingview.comsession cookies - Fire HTTP requests from Node directly with those cookies in a
Cookieheader — no browser, no CORS preflight
This was discovered the hard way: page-context fetch() from any TradingView page is blocked by CORS preflight, even though the website itself uses these endpoints. The lib/cookies.js module implements this auth flow once; commands then call tradingViewFetch(url, init).
Endpoint families used:
scanner.tradingview.com/{market}/scan2— quotes, options, screener (POST)news-headlines.tradingview.com/v2/{headlines,story}— news (GET)pricealerts.tradingview.com/{list_alerts,...}— alerts (GET)www.tradingview.com/api/v1/symbols_list/...— watchlists (GET)symbol-search.tradingview.com/symbol_search/v3/— search (GET)
Scanner responses arrive in the standard {fields, symbols} compressed form; field positions are read from the response — never hard-coded. The options chain endpoint specifically requires index_filters: [{name:'underlying_symbol', values:[...]}] + filter2 boolean composition, captured via Network domain inspection.
Auth model
No bearer token, no API key. The adapter relies entirely on the desktop app's logged-in session. Subscription tier matches what the user sees in the app — free / Essential / Plus / Premium tiers may return a subset of options data for some symbols.
Status
v0.1 — verified live against TradingView desktop app on macOS. All 12 commands smoke-tested end-to-end (quote → MU @ $746.81, options-chain → 7,426 contracts, news → 200 headlines, screener → top mcap, etc.). Wire shapes are the actual ones the desktop app uses (captured via CDP Network domain).
Known limitations:
- macOS only (
launchusesopen -a TradingView). chart-statesymbol/interval detection is best-effort — DOM selectors may need adjustment as TradingView updates the UI; the layout id and URL are always correct.- No tier-degraded gracefully — empty options chains may indicate the logged-in account's tier doesn't include that symbol's options.
Layout
opencli-plugins/tradingview/
├── opencli-plugin.json # plugin manifest
├── package.json # Node package (type: module)
├── lib/
│ ├── cookies.js # CDP Storage.getCookies harvest + tradingViewFetch helper
│ ├── cdp.js # CDP tab finder, Runtime.evaluate, Page.captureScreenshot
│ ├── scanner.js # POST helpers, {fields,symbols} decoder, screener body builder
│ ├── symbols.js # OPRA parser, expiry helpers
│ └── news.js # /v2/headlines + /v2/story + AST→text walker
├── launch.js # spawns TradingView with --remote-debugging-port
├── status.js # CDP /json + tab filter
├── quote.js # global/scan2 → spot
├── options-chain.js # options/scan2 → chain (full or ATM band)
├── options-expiries.js # options/scan2 → expiry list
├── screener.js # {market}/scan2 generic screener
├── search.js # symbol-search/v3
├── news.js # /v2/headlines (list) + /v2/story (--id)
├── watchlists.js # api/v1/symbols_list/{all,custom/<id>,colored/<c>}
├── alerts.js # pricealerts.tradingview.com (read-only)
├── chart-state.js # CDP Runtime.evaluate → layout_id, symbol, interval, url
├── screenshot.js # CDP Page.captureScreenshot → PNG
└── tests/
├── symbols.test.js # OPRA parser, expiry helpers
├── scanner.test.js # decoder, normalize, ATM-band slicer, body builders
├── screener.test.js # buildScreenerBody (limit clamping, sort, filter, tickers)
├── news.test.js # AST walker, headline normalize, epoch helpers
├── cookies.test.js # endpoint resolution, header constants
└── alerts.test.js # normalizeAlerts (live `r:[]` shape + fallbacks)
License
MIT