Back to home@JohnXu22786

market-watch

Financial market monitor for DeepSeek Harness (dsh bundle): real-time quotes, local watchlist, threshold alerts, periodic polling, ASCII/mermaid charts for A-share stocks, indices and crypto.

Stars
0
Language
TypeScript
Created
Aug 20, 2026
Updated
Aug 20, 2026

Introduction

dsh-market-watch

English · 简体中文

A financial market monitor bundle for DeepSeek Harness (dsh): real-time quotes, a local watchlist, threshold alerts, periodic polling, and in-chat ASCII/mermaid charts for A-share stocks/indices and cryptocurrencies — using free public data sources only. This is the first market/finance data plugin in the dsh ecosystem.

  • Quote — latest quotes for stocks, indices, and crypto via free sources (Tencent qt.gtimg.cn for CN securities, CoinGecko for crypto).
  • Watchlist — locally persisted watch items (code / name / market / kind), shared by the plugin and the CLI.
  • Alerts — threshold rules (changePercent / price, gt/gte/lt/lte) evaluated on every poll, with per-rule cooldowns. Delivery: a typed harness event market-watch/alert plus optional injection into live agent sessions.
  • Polling — timer-based periodic refresh of the whole watchlist (overlapping ticks are dropped; free sources are rate-limit friendly).
  • Charts — ASCII column charts, sparklines, and mermaid xychart-beta blocks rendered in chat.
  • Dual entry — six dsh tools (quote, list, watch, unwatch, alert, chart) and a standalone CLI (dsh-market-watch) over the same data.

Data sources and latency

MarketSourceNotes
Shanghai / Shenzhen / Beijing stocks & indicesTencent qt.gtimg.cn, web.ifzq.gtimg.cnFree endpoints; quotes may lag the tape by seconds to minutes. Daily bars are qfq (forward-adjusted) for stocks, raw for indices.
CryptoCoinGecko public APIFree tier is rate limited (calls are spaced by coingeckoDelayMs, Retry-After honored). Prices may lag; OHLC from market_chart is bucketed to UTC days.

All quotes carry a per-source disclaimer (delayNote). Nothing here is investment advice; never trade on delayed free data without verification.

Requirements

  • Node.js ^22.19 || >=24
  • dsh >=0.1.0-rc.6 with the web or headless profile

Install as a dsh bundle

A bundle is an npm package whose manifest declares dsh.bundle.patch (this package ships cordis.patch.yml plus a lib/ build). Two typical paths:

# 1. From a local checkout of this repo:
pnpm build                # or: npm run build
dsh plugin --profile web add .  # relative/absolute path to this directory

# 2. Git-hosted installs run the prepare script on install; pnpm >= 10 blocks
#    build scripts until allowlisted — add to the profile's pnpm-workspace.yaml:
#      allowBuilds:
#        dsh-market-watch: true
#    then:
dsh plugin --profile web add github:some-owner/dsh-market-watch

dsh plugin adds the package to the profile's dsh.profile.bundles list because it declares dsh.bundle; the patch inserts the market-watch row and the plugin's tools appear in every agent prompt after a restart.

Verify:

dsh config dump | grep market-watch   # row present

Configuration

Every option has a default; the bundle row ships without a config section. Override by id in your profile's cordis.patch.yml — remember a patch replaces the whole config value, so restate every key you keep (copy examples/cordis.patch.example.yml):

KeyDefaultMeaning
enabledtrueMaster switch for the plugin.
pollIntervalSeconds60Poll period (schema: 5..86400).
dataDir$DSH_HOME/market-watchDirectory holding watchlist.json.
timeoutMs10000Per-request network timeout.
maxRetries2Extra attempts after the first try.
retryBackoffBaseMs500Exponential backoff base.
vsCurrencyusdCrypto quote currency (CoinGecko id).
coingeckoDelayMs1200Min spacing between CoinGecko calls.
agentNotifytrueDeliver alerts into live dsh agent sessions.
agentWakeupfalseWake idle agents on alert (followup) instead of quiet inject.

Tools

Registered on ctx.tools; their schemas join the system prompt automatically.

ToolPurpose
quoteLatest quotes for codes (array), e.g. ["sh600000","000001","bitcoin"]. Optional days appends a sparkline per instrument (one history request each).
listThe local watchlist.
watchAdd instruments: codes (array), optional market (cn/crypto), kind (stock/index/crypto), name.
unwatchRemove one instrument by code.
alertManage rules: action = list | add | remove. add needs code, field (changePercent/price), op (gt/gte/lt/lte), value, optional cooldownSeconds (default 300) and note; remove needs the rule id from list.
chartcode, optional days (default 30), format (ascii/mermaid), width, height.

Accepted code forms for CN instruments: sh600000, 600000.sh, 600000.ss, 600000 (prefix inferred from the leading digit), 000001 with kind: index for the Shanghai Composite. Everything else is treated as a CoinGecko id (bitcoin, ethereum, …).

Tools never throw for expected failures — they return {ok:false, error} so the model can act on the message.

Alerts

Rules live in the same file as the watchlist and are evaluated on every poll. A rule fires when the comparison holds and the cooldown window since the last trigger has elapsed; lastTriggeredAt is persisted.

Delivery channels (both best-effort, failures contained):

  1. Harness event — ctx.emit('market-watch/alert', alert). Any extension can listen:

    ctx.on('market-watch/alert', (alert) => { /* alert.message, alert.quote, alert.rule */ })
    
  2. Agent sessions — when ctx.agents is mounted, every live agent receives the alert as a plugin-sourced user/message: quiet context for the next step (agent.inject) by default, or a full follow-up turn with agentWakeup: true.

CLI

dsh-market-watch runs on the same data directory as the plugin, so commands act on the exact state the plugin polls.

dsh-market-watch quote sh600000 bitcoin --days 5
dsh-market-watch watch sh600000 bitcoin --name "BTC"
dsh-market-watch list
dsh-market-watch unwatch sh600000
dsh-market-watch alert list
dsh-market-watch alert add bitcoin --field price --op gte --value 70000 --cooldown 600
dsh-market-watch chart sh600000 --days 30 --format mermaid
dsh-market-watch poll --once          # single pass (cron-friendly)
dsh-market-watch poll --interval 300  # keep polling every 5 min

Global flags: --data-dir <path> (or MARKET_WATCH_DATA_DIR), --help, --version. Exit codes: 0 ok, 1 runtime error, 2 usage error.

Data files

<dataDir>/watchlist.json — JSON document {version, items, rules}. Writes are atomic (temp file + rename), serialized through a promise chain, and a corrupt file is quarantined (watchlist.json.corrupt-<ts>) instead of wedging the plugin. Because the plugin and the CLI share one file, the engine re-reads it on every poll/json quotation, so edits made in a second process become visible without a restart.

FAQ

  • Which data sources are used, and how fresh are quotes? A-share stocks and indices come from Tencent's public quote endpoint; crypto comes from CoinGecko. See "Data sources and latency" above for the refresh cadence and the documented staleness limits.
  • Why is a symbol not recognized? Symbols are normalized case-insensitively (e.g. sh600000 / 600000 for an SSE stock, bitcoin / BTC for crypto). Run dsh-market-watch list --known (or the market_known tool) to see the accepted forms; symbols outside the provider's universe are rejected.
  • My alert did not fire. Alerts are evaluated on poll ticks; check the rule operator (gte/lte) and --cooldown, and that the field (e.g. price) exists in the quote shape. Alerts can be listed with dsh-market-watch alert list or the market_alerts tool.
  • Where is my watchlist stored? In <dataDir>/watchlist.json (dataDir defaults to the dsh profile data dir, or MARKET_WATCH_DATA_DIR / the --data-dir flag). Writes are atomic and corrupt files are quarantined.

Development

npm install
npm run typecheck   # tsc --noEmit
npm test            # vitest (all network paths mocked)
npm run build       # tsc -> lib/
npm run check       # typecheck + test + build

Layout: src/core/ is framework-free (types, symbols, formatting, HTTP client, JSON store, chart renderers, providers, engine) so the CLI and tests share it without importing dsh; src/dsh/ adapts the core to Cordis (tools, poller, notifier, entry point); src/cli/ is the standalone binary.

License

MIT — see LICENSE.