Watchlist panel for A-share, Hong Kong and US quotes plus Eastmoney boards, with intraday sparklines and an agent stock_quote tool.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:AhaCrazy/dsh-stock-quotes
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
中文 | English
A DeepSeek Harness plugin that shows live quotes for a watchlist of stocks in a sidebar data panel, and registers a stock_quote tool so the agent can answer "what is 贵州茅台 at right now" inside the conversation.
- Panel: A-shares, Hong Kong and US symbols in one list — price, change, change %, open / high / low, turnover; 15 s auto-refresh; right-click menu, drag to reorder, multi-select batch actions.
- Tool:
stock_quotereads one or several symbols (or the configured watchlist) in a single batched request. - Neutral by default: the sidebar entry is called
数据("Data") with a plain table glyph, and the display name is configurable. It reads as a generic data view rather than a stock ticker.
Quotes are delayed/snapshot data from a public endpoint. For information only — not investment advice, not for trading decisions.
Requirements
- DeepSeek Harness (0.2.x, with the
plugin_managertool) - No API key, no extra dependencies. The Host half imports nothing outside its own package.
Install
git clone https://github.com/AhaCrazy/dsh-stock-quotes.git
Then, from a DSH session, install the bundle by its absolute directory:
plugin_manager action: install_bundle target: <path-to>/dsh-stock-quotes
The sidebar icon appears once the client module loads — reload the page if it does not show up immediately. stock_quote shows up in the agent's tool list on the next request.
To remove it:
plugin_manager action: remove_bundle target: dsh-stock-quotes
Panel actions
| Action | How |
|---|---|
| Add | Type a symbol or board name in the top input, press Enter |
| Delete | Right-click a row → menu → Delete (there is no per-row ✕ button) |
| Reorder | Drag the ⠿ handle; a brand-colored line shows the drop position — or use the right-click menu's move items |
| Multi-select | Checkbox on each row; the header checkbox selects / clears everything |
| Batch | With ≥1 selected, a bar appears: delete selected / move to top / move to bottom / clear |
| Other menu items | Copy symbols (newline-joined), select all, clear selection |
| Charts | The "Charts" button in the toolbar toggles a per-row intraday line |
The context menu is selection-aware: if the right-clicked row is part of a multi-selection, delete/move/copy act on the whole selection and the labels carry the count; otherwise they act on that one row.
Order and membership persist in the browser (localStorage, key dsh-stock-quotes/watchlist). Rows always render in watchlist order and quotes are mapped by symbol, so reordering can never desynchronize a code from its price.
Charts
The Charts button in the toolbar toggles a per-row intraday line (today's session). The choice is stored in localStorage (chart in dsh-stock-quotes/prefs) and is on by default.
- Data comes from Eastmoney's intraday endpoint; A-shares, Hong Kong, US and boards all work (US shows the latest session)
- The x axis is the whole session, not the data stretched to fill the box: A-shares / Beijing / boards are 240 minutes (09:30–11:30, 13:00–15:00), Hong Kong 330 (09:30–12:00, 13:00–16:00), US 390 (21:30–04:00 Beijing time). At 11:30 the line therefore stops half way and the blank right side is the part that has not traded yet; it only fills at the close
- Refreshed every 60 seconds, deliberately not tied to the 15-second quote tick, so it cannot become a request storm
- Colour follows the day's move — red up, green down, neutral when flat — matching the number columns
- With charts off, no trend request is made; only the numbers remain
- A row whose series has not arrived yet keeps an empty cell, so columns never shift
- Hover a sparkline to read it: a crosshair follows the pointer and that row's price / change / % cells temporarily show the minute under it (the code line shows the timestamp, e.g.
sh600519 · 11:30), snapping back when the pointer leaves
Focus chart (click a row)
The sparkline only shows shape. Click any row and a full-width chart for that symbol opens above the table; click the row again or press × to close it.
- Y axis ticks on both the scale and the grid, plus a dashed previous-close line
- The time axis follows the instrument's session: A-shares
09:30 / 10:30 / 11:30·13:00 / 14:00 / 15:00; Hong Kong and US label their own sessions - Hover crosshair: the vertical line and dot snap to the nearest minute and the line underneath reads
time · price · ±% vs previous close · average · volume - The header shows the name, the current price and the session's high / low
- 1D / 5D switch: five-day mode splits by trading day and labels dates instead of the clock
- One-day mode also draws the average price line (dashed)
Settings
Everything lives on Settings → Plugins → "数据面板" and applies immediately:
| Setting | Meaning |
|---|---|
| Display name | One name for the sidebar label, panel heading and notices, default 数据. Whitespace-collapsed, capped at 24 characters |
| Refresh interval | 5 / 10 / 15 / 30 / 60 s; consecutive failures back off automatically (up to 2 minutes) and reset on success |
| Up / down colours | Red up / green down (China) or green up / red down (international) — numbers and chart switch together |
| Visible columns | Open / high / low / turnover can be hidden; name, price, change, percentage and chart stay |
| Move alert threshold | Show a banner when a symbol's daily move exceeds this percentage; 0 disables it |
| Import / export watchlist | JSON in a text box ({"version":1,"symbols":[...]} or a plain array of strings), so a list can move between machines |
Preferences live in localStorage under dsh-stock-quotes/prefs.
Sorting: click the name / price / change / percentage / turnover headers to sort (descending → ascending → unsorted). A sorted table is a read-only view, so drag-reorder asks you to clear the sort first.
Keyboard: Tab to a row, Enter or Space opens the focus chart, Esc closes it.
Symbol spellings
| Market | Spellings | Examples |
|---|---|---|
| Shanghai | 6 digits, sh prefix, .SH/.SS suffix |
600519, sh600519, 600519.SH, 688981, 900901 |
| Shenzhen | 6 digits, sz prefix, .SZ suffix |
000001, sz000001, 000001.SZ, 300750 |
| Beijing | 6 digits, bj prefix, .BJ suffix |
430047, 830799, 920001 |
| Hong Kong | 1–5 digits, hk prefix, .HK suffix |
00700, 700, hk00700, 00700.HK |
| US | letters, us prefix, .US/.O/.N suffix |
AAPL, usAAPL, AAPL.US, BRK.B (matched across NASDAQ / NYSE / AMEX) |
| Raw secid | market.code |
1.600519, 116.00700 |
Ambiguous bare six-digit codes: both markets are tried and the first that answers wins. So 000300 (沪深300, Shanghai only) falls through to 1.000300, while 000001 exists on both and defaults to Shenzhen (平安银行) — write sh000001 or 000001.SH for the Shanghai index. An explicit prefix or suffix is authoritative and never falls back, so a wrong market reports "not found" rather than silently picking another listing.
Boards (板块)
Eastmoney's industry and concept boards come through the same quote endpoint, and the panel can add them directly:
| Spelling | Examples |
|---|---|
| Eastmoney board code | BK1036 (半导体), BK0891 (国产芯片) |
| Board name (panel only) | type 半导体, 白酒, 存储芯片 — exact name match first, then a unique substring match |
| Raw secid | 90.BK1036 |
Three things to know:
- 同花顺's board codes (
88xxxx, e.g.881121) are a proprietary encoding with no public mapping, so they cannot be added as-is — use the name or the Eastmoney code instead:881121is 半导体, so type半导体orBK1036. - The two sources have different constituents and weights, so the index level and change will differ (measured at the same moment: Eastmoney 半导体
+3.47%, 同花顺+3.25%). Matching 同花顺 exactly is not possible. - Name lookup happens in the panel only;
stock_quotetakes the code, e.g.BK1036.
Search (add by name)
You do not need to know the code — typing in the input pops suggestions (name + canonical code) and one click adds the entry:
| Typed | Suggestions |
|---|---|
茅台 |
贵州茅台 sh600519 |
半导体 |
半导体 BK1036 (plus 半导体材料 BK1325 and others) |
BK13 |
半导体材料 BK1325 |
600519 |
added directly (an exact code wins, no picking needed) |
Ranking: exact name → name prefix → name substring → code prefix.
The suggestions come from data/securities.json in this repository (~11k rows: A-shares, indices, Hong Kong, industry and concept boards). The panel fetches it once from jsDelivr / raw.githubusercontent and caches it for a day. The file is generated:
node scripts/build-index.mjs # needs access to push2.eastmoney.com
Re-run and commit after new listings appear. When the index cannot be fetched (offline, blocked), adding by code and by board name still works.
Coverage
The data comes from Eastmoney's public quote endpoint, so what you can add is what it covers:
- ✅ A-shares, Beijing, Hong Kong, US, indices, ETFs / LOFs, convertible bonds, B-shares, boards (
BKxxxx) - ❌ Delisted or retired codes (e.g.
110043), off-exchange fund NAVs, futures, options, FX - ❌ Chinese stock-name search: not supported (the public search endpoints send no CORS header, so the browser cannot read them) — use a code; board names are the exception, see above
If a code you can see in 同花顺 does not resolve, try it with its full suffix (600519.SH); if that still fails, the data source does not carry it.
Configuration
cordis.patch.yml ships a watchlist that stock_quote falls back to when the model calls it without arguments:
- insert:
- id: stock-quotes
name: 'dsh-stock-quotes'
config:
defaultSymbols:
- sh000001
- sh600519
- sz300750
- hk00700
- usAAPL
The panel keeps its own watchlist in the browser, independently of this list: the config is for the agent, the panel is for looking.
How it works
| File | Role |
|---|---|
package.json |
Bundle manifest: dsh.bundle.patch inserts the Host row, dsh.client makes the Web app load the browser half |
cordis.patch.yml |
Loader patch: inserts the stock-quotes row with the default watchlist |
index.js |
Host half: registers stock_quote as a raw ToolDefinition (no imports outside the package) |
quotes.js |
Pure data layer: symbol resolution, batched fetch, formatting |
client.js |
Browser half: main panel, plugins.bundle.config settings card, sidebar.panellist icon |
locale/{zh,en}.json |
Plugin-manager card title and description |
Two design notes worth knowing if you modify it:
- No bare
@deepseek-ai/...imports in the Host half. A bundle linked into a profile from outside it does not resolve those specifiers, so the row would fail to import. It registers a rawToolDefinitioninstead. - The client half does not import any Harness client package. It writes its own controls with theme tokens (
--dsw-alias-*) only, which keeps it stable across Harness versions.
Tests
npm test
tests/quotes.test.mjs— symbol resolution, batching, formatting and cancellation. The deterministic part needs no network, and the live section is skipped when the endpoint is unreachable.tests/render.test.mjs— the tool definition and the text it renders: two decimals, signed changes, an em dash for missing fields, and no throw on degenerate input.tests/client.test.mjs— emulates the module loader, the locale service, the slot registry and React, then asserts what the plugin registers, what its components render, and the reorder/move list transforms.
The Host half's full contract check needs packages from a DeepSeek Harness installation, so it is kept out of this repo.
tests/meta.test.mjs— release consistency: the version matches the index version pinned in the code, the changelog has an entry for it,filescovers what must ship, there are no runtime dependencies, and the index is well formed.
Stability, data source and disclaimer
- Quotes come from Eastmoney's public endpoints (
push2/push2his). They are unofficial, unauthorised and carry no SLA: they may rate-limit, change fields or disappear. The plugin backs off and degrades gracefully on HTTP errors, but cannot promise availability. - The search index is a snapshot generated in this repository (
data/securities.json) and fetched from a CDN pinned to the release tag. Re-runnode scripts/build-index.mjsand publish when new listings appear. - Data may be delayed or wrong. This plugin is for looking at prices only: it is not investment advice and must not be used for trading decisions. Any loss from using it is the user's own.
- The plugin collects and reports nothing; the watchlist and settings stay in the browser's
localStorage.
License
MIT — see LICENSE.
Links
More in this category
zhu1090093659/dsh-web#packages/dsh-task-board★ 9262
Task board for the dsh web GUI: a sidebar multi-column kanban whose cards run in real DSH agent sessions and can also be scheduled with cron expressions, executed host-side even with the browser closed.
zhu1090093659/dsh-web#packages/dsh-web-all★ 9262
Plugin and skin collection for the DSH Web UI: task board, Git graph, right-side panel, remote mobile UI, pet, live token stats, and a skin center.
MeteorNOX/DeepSeek-Balance-Whale-Widget★ 5677
A fixed-corner whale widget for the DSH web GUI — balance, today's usage and per-turn cost with peak/off-peak pricing, editable balance-alert and daily-budget bubbles, a module-based custom bubble queue with A/B weighted choices and random lines or images, 30+ vendor templates (OpenAI, OpenRouter, Kimi, SiliconFlow, Ark, Zhipu, MiniMax and more) with per-model balance and subscription quota, plus task-end sound, imported audio, custom roles and a resource manager. Local-only, no telemetry.
ccch1mneyyy/dsh-TUI★ 5125
Claude Code-style full-screen terminal UI: pixel-whale header, live status line, and streaming thought expansion.
omdsh-dev/DSH-better-sidebar★ 4413
Full sidebar workbench with file rendering and editing, terminal, Git, and subagents; third-party plugins can register new tabs.
Devin-AXIS/deepseek-design#deepseek-idesign★ 1491
Visual design studio for websites, app prototypes, posters, cards, reports, and magazines, with templates, direct element editing, selection-aware AI draft handoff, and export.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.