Tutorial

A-Share Data in Node.js / TypeScript with the Official SDK

The official Node SDK is live: `npm install ashareapi`. Five endpoints need no key, it has zero runtime dependencies (native `fetch`), ships full TypeScript types, returns arrays of objects, accepts forgiving symbol formats, and 5 exception types tell you exactly what to do.

Install

bash
npm install ashareapi
# or: pnpm add ashareapi / yarn add ashareapi
  • Requires Node.js >= 18 (native `fetch`; 20 LTS or newer recommended)
  • Zero runtime dependencies — about 12 KB installed, no supply-chain surface
  • Both ESM and CommonJS work (`import` and `require`), with bundled `.d.ts` types
  • ⚠️ Server-side only (Node scripts / Next.js server routes / backends) — in a browser your API key would be exposed, so no browser build is provided

Up and running in 30 seconds (free endpoints need no key)

Five free data endpoints: `quote` / `kline` / `hot` / `marketOverview` / `changedist` — no signup, no key, works immediately after install.

TypeScript / ESM (runs as-is)
import { AShareAPI } from "ashareapi";

const cli = new AShareAPI();                  // free endpoints need no key
const bars = await cli.quote("sh600667");     // real-time quote
console.log(bars[0]);                         // { date, open, last, high, low, volume, amount, turnover }

console.log(await cli.kline("600667.SH", "day", 5));  // any symbol format works
console.log(await cli.hot(10));                       // hot list
console.log(await cli.changedist());                  // up/down distribution

CommonJS form (`require`)

JavaScript (CJS)
const { AShareAPI } = require("ashareapi");

(async () => {
  const cli = new AShareAPI();
  const rows = await cli.kline("sh600667", "day", 3);
  console.log(rows[0].date, rows[0].last);
})();
  • The `exports` map declares both `import` and `require` entry points — you do not have to change module systems to use this package

Two naming styles, same methods (drop-in from the Python SDK)

Multi-word methods expose snake_case aliases (identical to the Python SDK names) — both spellings are the same method, so code copied from the Python docs works unchanged.

`marketOverview(type)`
`market_overview(type)`
`/v1/market-overview`
`marginTrade(code, date)`
`margin_trade(code, date)`
`/v1/margin-trade`
`blockTrade(code, date)`
`block_trade(code, date)`
`/v1/block-trade`
`sectorValuation(code)`
`sector_valuation(code)`
`/v1/sector-valuation`
`industryChain(mode, topic, code)`
`industry_chain(mode, topic, code)`
`/v1/industry-chain`

Symbol formats: three spellings accepted

`sh600667`
`sh600667`
Native form (market prefix + code)
`600667.SH`
`sh600667`
Common suffix style, converted automatically
`600667`
`sh600667`
Bare 6 digits inferred from the first digit: 5/6 → Shanghai, 0/3 → Shenzhen, 4/8 → Beijing

Key-required endpoints

TypeScript
import { AShareAPI } from "ashareapi";

const cli = new AShareAPI({ apiKey: "ct-your-key" });   // or set ASHARE_API_KEY
const rows = await cli.screen("", "low_pe", 10, "ROETTM");  // expr, preset, limit, orderby
console.table(rows);

console.log(await cli.fund("sh600667"));      // money flow + boards + block trades + margin
console.log(await cli.finance("sh600667"));   // three financial statements
console.log(await cli.lhb("institution"));    // top-trader board, institutions
  • Get a key on the [pricing page](https://ashareapi.com/pricing/) (from ¥9.9)
  • 32 endpoints = 32 methods, named after the endpoint (`/v1/margin-trade` → `marginTrade()`)
  • Full list in the [endpoint reference](https://ashareapi.com/endpoints/)

Return shape: an array of objects (not a DataFrame)

For the full envelope (with `elapsed_ms` / `source` / `tier`) construct with `new AShareAPI({ raw: true })` — methods then return the raw response object instead of an array.

TypeScript
const rows = await cli.kline("sh600667", "day", 3);
// [
//   { date: '2026-09-23', open: '20.10', last: '20.59', high: '20.72', low: '19.45', ... },
//   { date: '2026-09-22', open: '20.63', last: '19.87', ... },
//   { date: '2026-09-21', ... }
// ]
Default return
`pandas.DataFrame` (or `list[dict]` without pandas)
`Row[]` (array of objects) — except `finance` (`Row[][]`) and `shareholder` / `calendar` (`{ tables, data }`)
Accessing values
`df["last"]` / `df.head()`
`rows[0].last` / `rows.map(...)`
Sync or async
Synchronous
Everything returns a Promise (`await`)

Error handling: 5 exception types that each say what to do

TypeScript
import { AShareAPI, AuthError, RateLimitError,
         UpstreamError, EmptyResultError } from "ashareapi";

const cli = new AShareAPI();
try {
  const rows = await cli.fund("sh600667");
} catch (e) {
  if (e instanceof AuthError) console.log(e.message);          // 401 -> key-required endpoint, get a key
  else if (e instanceof RateLimitError) console.log(e.message); // 429 -> slow down / solve a PoW challenge / upgrade
  else if (e instanceof UpstreamError) console.log(e.message);  // upstream fetch failed (failed over, not billed) -> retry once
  else if (e instanceof EmptyResultError) console.log(e.message); // no data right now (e.g. no block trades today) -> not billed
  else throw e;
}
  • Built-in retries: `429` / `5xx` / network errors back off exponentially 3 times (0.5s / 1.5s / 4s)
  • `ok:false` (upstream fetch failure) is never retried — the backend already failed over
`AuthError`
401 / key-required endpoint called without a key
Get a key, or use the free endpoints
`RateLimitError`
429, tier rate exceeded
Slow down; solve a PoW challenge; or upgrade
`UpstreamError`
Upstream fetch failed (we failed over, not billed)
One retry usually fixes it
`EmptyResultError`
Request succeeded but there is no data right now
Change conditions or retry later, not billed
`APIError`
Anything else (network / 5xx after retries)
Read the message

Using it in a Next.js server route (server-side only)

app/api/quote/route.ts
import { NextResponse } from "next/server";
import { AShareAPI, AuthError, RateLimitError } from "ashareapi";

const cli = new AShareAPI();   // reads process.env.ASHARE_API_KEY

export async function GET(request: Request) {
  const code = new URL(request.url).searchParams.get("code") ?? "sh600667";
  try {
    const [quote, technical] = await Promise.all([cli.quote(code), cli.technical(code)]);
    return NextResponse.json({ ok: true, code, quote: quote[0], technical: technical[0] });
  } catch (e) {
    if (e instanceof AuthError) return NextResponse.json({ ok: false, error: "Missing or invalid key" }, { status: 401 });
    if (e instanceof RateLimitError) return NextResponse.json({ ok: false, error: "Rate limited" }, { status: 429 });
    throw e;
  }
}
  • Keep the key in a server-side env var (`.env.local`) — never in `NEXT_PUBLIC_*`, which ships to the browser bundle
  • `Promise.all` fetches several endpoints concurrently — much faster than sequential calls

Common mistakes and boundaries

  • `401` on a key-required endpoint → no key supplied: only 5 endpoints are free
  • `429` → anonymous limits are low (5/min); one PoW challenge (`cli.challenge()`) raises it to 60/min, or upgrade the tier
  • `EmptyResultError` is not a failure: it means "there is genuinely no such data right now" (e.g. no block trades today) — not billed, do not treat it as an error
  • Forgetting `await`: every method returns a Promise, so `console.log(cli.quote(...))` prints a Promise, not data
  • Data date: on a market holiday the date will not say "today"; read the `date` field to know which session the data belongs to
  • Units: `volume` is in lots (×100 = shares) · `amount` is CNY · ratio fields are percentages (`20` = 20%)
  • Minute bars: only daily / weekly / monthly are provided; minute-level is out of scope (stated plainly)

FAQ

Is the SDK free?

The SDK itself is free (MIT). Five free endpoints (quote / K-line / hot list / market overview / up-down distribution) need no key and no signup. The other 25 endpoints need an API key (from ¥9.9); the SDK charges nothing extra.

Do I need to install dependencies?

No. Zero runtime dependencies — it only uses Node native `fetch` (hence Node >= 18). About 12 KB installed, no transitive dependencies and no supply-chain surface.

Can I call it from the browser?

Technically our API allows cross-origin calls, but it is not recommended and not supported: calling from a browser puts your API key in front-end code and network requests, which is the same as publishing it. Call from the server (Node / Next.js server route / cloud function) and pass results to the front end. No browser build is provided on purpose.

Are the TypeScript types complete?

Yes. Bundled `.d.ts` files: your editor autocompletes all 32 methods and their parameters. Common row types (`Row` / `QuoteRow` / `Envelope`) are exported, so `import type { Row } from "ashareapi"` works.

How is this different from the Python SDK?

Same backend, same 32 methods, same 5 exception types, same retry policy. The only differences are language conventions: the JS methods are primarily camelCase (with snake_case aliases), everything returns a Promise, and results are arrays of objects rather than DataFrames.

How do I upgrade?

`npm install ashareapi@latest`. For the latest version and the full change history, see the [changelog](/en/changelog).

Last updated: 2026-09-23

Code and return shapes come from real runs of the SDK (installed 2026-09-23 from the packed tarball and verified in both ESM and CJS: quote returned 30 rows, hot 3 rows, marketOverview("valuation") 8 rows, and a key-required endpoint correctly threw AuthError without a key).