Lightweight HK/US stock real-time K-line charting inside VSCode, powered by Futu OpenD.
- Two stacked panels — watch two symbols side by side (e.g. an HK ETF and a US stock)
- Real-time K-line + intraday — candlestick with volume, or intraday price/average/volume with a previous-close reference line
- Multiple periods — 1m / 5m / 15m / 30m / 60m / day; switchable per panel
- Live updates — incremental bar refresh over WebSocket, no manual reload
- Runs inside VSCode — a webview panel; no external browser or background daemon to install
- VSCode 1.85+
- Futu OpenD running locally (
127.0.0.1:11111) with the quote session logged in (qot_logined=true) - Python 3.11 that can
import futu, fastapi, uvicorn-
On macOS, create the venv with
--system-site-packages, becausepip install futu-apiinto a plain venv breaks (it uses legacysetup.py install). The system Python'sfutu-apiworks; the venv inherits it:python3 -m venv --system-site-packages .venv .venv/bin/python -m pip install fastapi 'uvicorn[standard]' websockets
-
Download the latest .vsix from Releases, then:
code --install-extension vs-kline-0.2.2.vsixOr install directly via URL:
code --install-extension https://github.com/xhqing/VS-KLINE/releases/download/v0.2.2/vs-kline-0.2.2.vsix-
Clone and install JS deps:
git clone https://github.com/xhqing/VS-KLINE.git cd VS-KLINE npm install -
Build:
npm run compile -
Press
F5to launch an Extension Development Host, then run vs-kline: Open from the command palette.
npm run package # produces vs-kline-<version>.vsix
code --install-extension vs-kline-<version>.vsix(Search vs-kline once published.)
Open Settings and filter by vs-kline:
| Setting | Default | Description |
|---|---|---|
vs-kline.pythonPath |
"" |
Python interpreter that can import futu. Empty = auto-detect (prefers .venv/bin/python). |
vs-kline.host |
127.0.0.1 |
Host the backend binds to. |
vs-kline.port |
0 |
Backend port. 0 = dynamic (recommended). |
vs-kline.defaultSymbols |
{c1:HK.02800, k1:K_5M, c2:US.AAPL, k2:K_15M} |
Default symbols for the two panels. k: RT → intraday. |
vs-kline.opendHost |
127.0.0.1 |
Futu OpenD host. |
vs-kline.opendPort |
11111 |
Futu OpenD port. |
vs-kline.retainContextWhenHidden |
true |
Keep the webview (and its WS) alive when the panel is hidden. |
vs-kline.stopOnClose |
true |
Stop the backend when the chart panel is closed. |
vs-kline.autoRestart |
false |
Auto-restart the backend on crash. |
Run from the command palette (Cmd/Ctrl+Shift+P):
- vs-kline: Open — start the backend (if needed) and open the chart panel
- vs-kline: Start Backend / Stop Backend / Restart Backend
- vs-kline: Backend Status — print state/port/pid to the
vs-klineoutput channel
VSCode extension (TypeScript)
activate → registers commands (lazy, on vs-kline.open)
vs-kline.open
→ BackendManager.start()
pythonFinder resolves .venv/bin/python (verifies import futu)
spawn: python -m uvicorn backend.server:app --port 0 --workers 1
parse "Uvicorn running on http://127.0.0.1:NNNN" → actual port
poll GET /health until opend ready
→ WebviewPanel loads webview/index.html
CSP connect-src: ws://127.0.0.1:NNNN http://127.0.0.1:NNNN (exact port)
injects window.__VSKLINE_WS__ / __VSKLINE_DEFAULTS__
lightweight-charts loaded via asWebviewUri + nonce
deactivate / close panel → BackendManager.stop(): SIGTERM → SIGKILL
Python backend (backend/, data layer unchanged)
server.py: OpenD host/port read from env vars
futu_source.py / registry.py: Futu source, timezone, subscription refcount
The data layer (Futu source, timezone conversion, subscription refcounting, the history/update/error WS protocol) is unchanged from v0.1.0 — the extension only swaps the host (browser → webview) and the lifecycle owner (launchd → extension subprocess).
- Futu OpenD (
futu-api, Python) — HK/US K-line + real-time push - Supported codes:
HK.*(Hong Kong,Asia/Shanghai),US.*(US,America/New_York)
- macOS first — the
--system-site-packagesvenv trick is macOS-specific; Windows/Linux are untested. - OpenD required — if OpenD isn't running or isn't logged in, the backend reports
opend=falseand charts won't load. - The .vsix does not bundle Python deps — you provide the Python environment (see Requirements).
- Dynamic port — the backend picks a free port on each start;
scripts/ws_client.pytakes the port as an arg for debugging.
- "No Python found that can import futu" — create a
--system-site-packagesvenv (see Requirements) or setvs-kline.pythonPath. - Charts empty / "OpenD not logged in" — start Futu OpenD and confirm the login; check the
vs-klineoutput channel. - Port in use — set
vs-kline.portto0(dynamic). - Logs — run vs-kline: Backend Status, or open the
vs-klineoutput channel.
If you use, fork, or redistribute this project, please credit the original author (Huaqing Xu / xhqing) and link back to the project: https://github.com/xhqing/VS-KLINE.
Copyright (c) 2026 All Contributors. Licensed under the MIT License.