DSH HUB
HomePlugin StoreRankingsPublish Guide
Plugin source
Back to catalog

Realyujie /

dsh-us-stocks

Verified

US stock market data tools for DeepSeek Harness, powered by yahoo-finance2

★ 6 Stars1 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@c2247325

dsh-us-stocks

English | 中文

dsh-us-stocks cover

US stock market data tools for DeepSeek Harness, powered by yahoo-finance2.

Gives the agent six first-class tools for quotes, price history, financial statements, analyst consensus, news and ownership — instead of leaving it to improvise against HTML pages.

Six tools for one ticker: quote, history, financials, analyst view, news, ownership. Same AAPL task: 31 calls in 213s without the plugin, 5 calls in 33s with it.

Before and after

One agent turn, same question, same model, same machine — the only variable is whether the plugin is installed. The task: price, three-month trend, recent quarterly financials, analyst rating and recent news for AAPL.

Without this plugin With this plugin
Steps 14 2
Tool calls 31 5
Wall clock 213.5s 33.2s
What it called 16 × web_search, 15 × bash one call to each tool the task needed

With no market-data tool available, the agent falls back on web search and shell commands, fetching and parsing one page at a time. Most of the remaining 33 seconds is model inference, which no plugin controls; data retrieval itself is 2.6s.

Acceptance benchmark — AAPL
Acceptance benchmark — AAPL

  ✅ get_quote           2016ms  305.93 USD (+0.2195%), mcap 4464.80B
  ✅ get_history          446ms  62 bars 2026-05-18..2026-08-14
  ✅ get_financials      2181ms  4 income / 4 balance / 4 cash-flow periods
  ✅ get_analyst_view    2492ms  buy from 41 analysts, target 322.2844
  ✅ get_news             632ms  8 headlines, latest "Google is using a $29 gadget to tighten its gri…"
  ✅ get_ownership       3135ms  66.48% institutional across 7709 filers, insiders net 35206 shares over 6m

  tool calls        6
  wall clock        3.14s (concurrent)
  payload           26.2 KiB across 6 results

Reproduce with npm run benchmark, optionally against another ticker: npm run benchmark -- TTMI.

Install

The lazy way

Say it to your DeepSeek Harness:

Install this plugin: https://github.com/Realyujie/dsh-us-stocks

The agent reads this README and runs the command itself. It will ask for filesystem permission on the way, because the profile directory sits outside the session workspace.

By hand

If dsh is on your PATH:

dsh plugin --profile web add dsh-us-stocks

If it is not — which is the case when Harness was started through npx, since the binary then only exists in the npx cache — call it through npx instead:

npx @deepseek-ai/dsh plugin --profile web add dsh-us-stocks

Every command below works the same way: prefix it with npx @deepseek-ai/dsh in place of dsh, or install the CLI globally once with npm install -g @deepseek-ai/dsh and use the short form throughout.

To update later:

dsh plugin --profile web update dsh-us-stocks

Restart the profile afterwards — plugins are resolved when the tree is composed at boot.

For local development, point the profile at a checkout instead. Changes take effect after npm run build and a restart:

dsh plugin --profile web add link:/absolute/path/to/dsh-us-stocks

dsh plugin forwards to pnpm inside the profile directory and keeps the profile's dsh.profile.bundles list in step, so no manual registration is needed.

The plugin registers server-side agent tools. It also ships a small browser half that draws the candlestick chart described under get_history; in a TUI or headless profile that half is simply absent and every tool still works.

Tools

Tool Returns
get_quote Last price, change, day range, volume, market cap, P/E, EPS, book value, dividend yield, 52-week range, moving averages, last and next earnings dates. For an ETF or mutual fund, also expense ratio, net assets, category, allocation, trailing returns and top holdings
get_history Daily/weekly/monthly OHLCV bars with adjusted close, plus dividends and splits in the window, as structured data points
get_financials Income statement, balance sheet and cash flow line items, quarterly or annual, with the reporting currency and trailing-twelve-month ratios
get_analyst_view Consensus rating, buy/hold/sell counts by month, price targets, forward EPS and revenue estimates, recent broker upgrades and downgrades, EPS beat/miss history
get_news Recent headlines with publisher, timestamp and link
get_ownership Insider/institutional split, largest institutional and fund holders with quarterly position changes, and insiders' six-month buying and selling

get_quote

Parameter Type Notes
ticker string, required e.g. AAPL, BRK-B

Earnings dates are reported as last_earnings_date and next_earnings_date separately, because upstream conflates them in one field. next_earnings_date_is_estimate marks a date projected from the reporting cadence rather than confirmed by the company. Across a ten-ticker sample it was true half the time, so it is worth checking rather than assuming either way.

currency is what the stock trades in; financial_currency is what the company reports in. They differ for ADRs, and only the latter applies to the figures in get_financials.

Analyst ratings are deliberately not part of this tool even though upstream returns one. Consensus ratings and price targets live in get_analyst_view, so a caller that only wants market data never has a recommendation put in front of it.

ETFs and mutual funds additionally return fund_expense_ratio_percent (with the category average beside it), fund_total_assets, fund_category, fund_family, fund_asset_allocation_percent, fund_trailing_returns_percent and fund_top_holdings. Those come from a second upstream call made only when the quote says the symbol is a fund, so an equity pays nothing for them; a fund quote costs roughly three times an equity one. If that call fails the quote is still returned, with a warning.

Three things about the fund fields are stated in a fund_notes block in the response itself, rather than only here, because whatever reads the numbers is reading the response:

  • trailing_pe, price_to_book, book_value_per_share and eps_trailing_twelve_months are holdings-weighted aggregates for a fund, not one company's figures. Left unlabelled, they get read as a valuation judgement on the fund.
  • The expense ratio is passed through as reported and is occasionally wrong — FXAIX was observed at 0.42% against a true 0.015%.
  • fund_trailing_returns_percent switches convention partway through, as upstream does: ytd through one_year are returns over that window, while three_year_annualized, five_year_annualized and ten_year_annualized are annualised. The keys say which, because the two differ by a factor of four over five years.
  • fund_top_holdings is capped at ten positions upstream, so fund_top_holdings_coverage_percent states how much of the fund they add up to. That share ranges from 14% (VXUS) to 73% (XLE) across the funds sampled, and fund-to-fund overlap cannot be computed from a partial list. Bond, commodity and inverse funds report no positions at all; the field is then absent rather than empty.

get_history

Parameter Type Notes
ticker string, required
range enum 5d 1mo 3mo 6mo 1y 2y 5y 10y max. Default 1y
start_date / end_date string yyyy-MM-dd; start_date overrides range
interval enum 1h 1d 1wk 1mo. Default 1d. One call covers ~5 weeks at 1h, ~2 years at 1d, ~8 at 1wk, ~35 at 1mo
limit integer Keep the most recent N bars, 1–500. Defaults to every bar in the window

Bars are ordered oldest to newest. date is yyyy-MM-dd for 1d/1wk/1mo, and a full ISO instant for 1h — several bars share a calendar day at that granularity, so a date-only label would print the same value for all of them.

interval: "1h" is separately capped by the upstream source at about 730 days of history, regardless of the requested window. A range or start_date older than that fails with invalid_argument rather than the truncation warning the other intervals get, since Yahoo refuses the request outright instead of returning a partial one.

In the Web UI the call renders as a candlestick chart — bodies, wicks, a volume band, price gridlines and per-bar OHLC on hover — drawn from the same payload the model receives, so the picture and the numbers cannot disagree. Colours follow the host theme, green rising and red falling. Chart labels follow the host language, English or Chinese; messages from the data source are shown verbatim, since they are written for the model as well as the reader. Elsewhere the call shows the host's generic result card; the tool's output is identical either way.

dsh-us-stocks rendering an AAPL candlestick chart in DeepSeek Harness

Every response carries a chart_note explaining this, because the model reads the returned data when deciding what to do next, not the tool description it read at call time. Without it, a model that got a chart in the Web UI has been observed spending a minute installing matplotlib into a virtualenv to build a second one, unaware the request was already satisfied.

Dividends and splits falling inside the returned window come back as dividends and splits; both keys are absent for symbols that have never paid or split.

The two price bases are not interchangeable. open/high/low/close are adjusted for splits only; adj_close is adjusted for splits and dividends. Over 2019–2026, 91 of 93 AAPL monthly bars have close ≠ adj_close, so mixing them in one calculation is quietly wrong. Every response states this in price_adjustment.

Bars are trimmed to fit the output budget rather than to a fixed count, since a bar costs 117–127 characters depending on price magnitude and interval. In practice a request for max returns 266–489 bars. When trimming happens, the warning names the next coarser interval to use for the full span.

get_financials

Parameter Type Notes
ticker string, required
period enum quarterly (default) or annual
statements array Any of income balance cash_flow. Default all three
limit integer Most recent N periods, 1–8. Default 4
detail enum summary (default, headline line items) or full (every reported field)

Upstream depth is fixed and cannot be widened by asking for an earlier start: about 5 periods of income statement and cash flow, 7 of balance sheet, quarterly or annual alike.

Every response carries reporting_currency. This is not always USD. An ADR files in its home currency while trading in dollars — TSM in TWD, SAP in EUR, BABA in CNY, NVO in DKK — so raw revenue is off by ~32x for TSM against a USD filer. If the currency cannot be determined the statements are still returned, with a warning not to assume USD.

A full trailing-twelve-month statement is not available: the upstream trailing period type returns periodType: "TTM", which fails yahoo-finance2's schema validation, and reading it would mean disabling result validation wholesale. TTM aggregates — revenue, gross profit, EBITDA, free cash flow and the margin, return, growth and leverage ratios — do come back, in the ratios block.

Margins, returns and growth rates in ratios are unitless fractions (0.27 means 27%). debt_to_equity_percent is the exception: Yahoo scales it by 100, so AAPL's 0.784x arrives as 78.445. It keeps the upstream value and carries the unit in its name rather than being silently rescaled.

get_analyst_view

Parameter Type Notes
ticker string, required

recommendation_mean runs 1–5 where 1 is Strong Buy and 5 is Strong Sell — a lower number is more bullish, which reads backwards if taken as a score out of five. Each response repeats the scale in recommendation_mean_scale rather than relying on the reader to know it.

Period codes count away from now in opposite directions: recommendation_trend uses 0m for this month and -1m for last month, while estimates uses 0q/+1q for the current and next quarter and 0y/+1y for the current and next fiscal year. earnings_surprises uses -1q for the most recently reported quarter.

rating_changes keeps the ten most recent broker actions, newest first; upstream holds hundreds. action is up, down, main (reiterated) or init (coverage initiated).

Prices here are in the trading currency (USD for US listings) even when the company reports in another — unlike the statement figures in get_financials.

ETFs and funds return no_data: analysts rate individual companies, so a fund never carries a rating, a price target or an EPS estimate. Fund detail belongs to get_quote.

get_news

Parameter Type Notes
ticker string, required
limit integer 1–10. Default 10

Headline metadata only. Article bodies are not fetched. Upstream returns at most 10 headlines regardless of what is requested, so 10 is both the default and the ceiling.

Only headlines that actually reference the symbol are returned. The upstream news search matches text, so a ticker that is also an ordinary word pulls in unrelated stories — searching ALL returned a Finnish bank's tender offer and a mineral resource update, KEY returned UK property filings, none of which mention Allstate or KeyCorp. Results are filtered against each article's related-tickers list, and when the symbol pass comes up short the company name is searched as well. That recovered ALL from 0 of 6 relevant to 6 of 6, and KEY likewise. The number of discarded headlines is reported as a warning; if every match is noise the tool fails with no_data and says so, rather than returning plausible-looking articles about other companies.

get_ownership

Parameter Type Notes
ticker string, required
detail enum summary (default) or full
limit integer Rows per list, 1-50. Default 10

summary returns the insider/institutional breakdown, the largest institutional and fund holders, and insiders' aggregate buying and selling over six months. insider_activity and institutional_activity are siblings: upstream reports both from one module, but a path reading insider_activity.net_institutional_shares would say one thing and carry another. Only the insider figures carry a period — upstream never states the window its institutional net spans. full additionally returns individual insider filings and the named insiders with their holdings; those filings are most of the payload, which is why they are opt-in.

Holder figures come from quarterly 13F filings and are as of each row's own report_date, not today. insider_activity aggregates every insider over the period, so it can be net positive while one well-publicised insider was selling — a distinction restated in ownership_note, because a model reconciling this against a news story needs to know the two are different measurements rather than a contradiction.

Institutional and insider filings are made against operating companies, so ETFs and funds return no_data. A fund's own holdings are in get_quote.

Response shape

Every tool returns a JSON string with a consistent envelope.

Success:

{
  "ok": true,
  "market": "us",
  "ticker": "AAPL",
  "as_of": "2026-08-14T09:28:31.204Z",
  "data": { "…": "…" },
  "warnings": ["Returned the most recent 455 of 11509 bars, the most that fits the tool output budget. …"]
}

Failure — never a bare exception:

{
  "ok": false,
  "market": "us",
  "ticker": "ZZZZ",
  "error": {
    "kind": "unknown_symbol",
    "retryable": false,
    "message": "No quote data for symbol \"ZZZZ\"."
  }
}

retryable is the field that matters to the model. It separates "this ticker genuinely has no such data, stop asking" from "the upstream hiccuped, the same call may work shortly".

kind retryable Meaning
unknown_symbol no Symbol does not resolve to any instrument
no_data no Symbol is valid but this dataset is absent (ETFs file no income statement)
invalid_argument no Argument the tool cannot honour
upstream_unavailable yes Upstream refused or errored transiently
rate_limited yes Upstream throttled the request
timeout yes Deadline or caller cancellation fired
response_too_large yes Payload exceeded the output budget even after the envelope was stripped
internal no Unclassified

Results above 64,000 characters are truncated: data is dropped, the envelope is preserved, and output_truncated plus original_characters tell the model to retry with a narrower query. get_history, whose payload scales with the requested window, trims its own bars against the measured size first, so it reaches that fallback only in pathological cases.

Configuration

enabled: true          # register the tools
market: us             # only "us" today
quoteTtlMs: 10000      # live quote cache lifetime
referenceTtlMs: 300000 # statements, bars, ratings and news cache lifetime

Caching is in-memory and per-process. Concurrent identical requests are collapsed onto a single upstream call, so an agent fanning six tools at one ticker does not make six redundant round trips. Failures are never cached.

Development

npm install
npm run typecheck
npm test            # unit tests, no network
npm run build
npm run test:live   # live smoke test against Yahoo, needs network
npm run benchmark   # AAPL acceptance benchmark

Requires Node >= 22.19.0.

Layout

src/
├── index.ts                    apply(ctx, config) entry point
├── config.ts                   schemastery config, incl. the market enum
├── datasource/us/
│   └── yahoo-client.ts         yahoo-finance2 wrapper: caching, cancellation, error typing
├── tools/                      one file per tool, plus shared shaping helpers
├── client/                     browser half: the candlestick card for get_history
└── util/
    ├── cache.ts                short-TTL cache with in-flight de-duplication
    ├── errors.ts               failure taxonomy and envelopes
    └── stringify.ts            output budget enforcement

Only US equities are supported. The datasource/<market>/ split, the market config enum and the opaque handling of ticker exist so another venue can be added without reshaping the plugin — but nothing else is implemented today.

Notes on the data source

Financial statements come from Yahoo's fundamentalsTimeSeries endpoint rather than the quoteSummary statement modules. Since late 2024 those modules return only a handful of income-statement fields and lag by a reporting period; for AAPL they gave 9 populated fields ending 2026-03-31, against 35 ending 2026-06-30 from the endpoint used here.

This is an unofficial, undocumented API. It can change without notice, and it is rate-limited. Data is provided as-is for research; it is not investment advice.

License

MIT

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

APIPublish GuideAbout
—/ 5

No ratings yet

Verified DSH bundle

Commit c2247325614a

Community comments

No comments yet. Be the first to write one.