npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cn-market-data

v1.3.0

Published

A-share and China ETF market data Facade (SH/SZ only): kline, order book, ticks, capital flow, margin financing, dividends. Hong Kong not supported.

Readme

cn-market-data

A-share / China ETF market data adapters for Node.js and Cloudflare Workers.

npm version

npm install cn-market-data

Architecture: see ARCHITECTURE.md.
Maintainer release steps: see PUBLISHING.md.
Changelog: see CHANGELOG.md.

Tests

All Facade tests hit real upstreams (no mocked network):

npm test

Coverage: assertMarketCode, getKlineBars (1d / 1w / 15m, stock + ETF), getOrderBook, getTradeTicks, getMinuteCapitalFlow, getDailyCapitalFlow, getMarginFinancingRecords, getDividendRecords (stock + ETF).

Market scope

| In scope | Out of scope | |---|---| | Shanghai / Shenzhen A-shares (sh######, sz######) | Hong Kong (hk#####) | | China-listed ETFs on SH/SZ (e.g. sh510300, sh515080) | US / other overseas markets | | | TradingView universe screening |

Facade entry points call assertMarketCode() first. Invalid codes throw immediately; they are never sent upstream.


Conventions

| Item | Rule | |---|---| | Stock / ETF code | sh###### / sz###### only (case-insensitive; normalized to lowercase) | | Currency | CNY yuan unless noted | | Volume | Shares (股) for stocks; fund units (份) for ETF dividends | | Custom runtime | Pass fetcher (same shape as fetch) for Workers / tests |

Upstream vendors are unofficial public endpoints. Expect rate limits and occasional schema drift.


Price adjustment (复权)

| Path | Adjustment | |---|---| | Day / week / month via Sina (primary) | Vendor default bars from CN_MarketData.getKLineData (not an explicit qfq/hfq switch) | | Day / week / month via Tencent (fallback) | 前复权 (qfq) — URL param ends with ,qfq | | Minute bars | Intraday raw prints; no historical adjustment |

If you need a guaranteed adjustment mode, prefer documenting which vendor path you hit, or pin behavior in your own layer.


Error semantics

| API | Invalid code | Upstream / empty data | |---|---|---| | assertMarketCode | throws | — | | getKlineBars | throws | Primary fails → fallback; if both fail, throws | | getOrderBook | throws | Both vendors empty → throws (没有五档行情数据) | | getTradeTicks | throws | Baidu empty → Tencent; may return [] or throw if Tencent fails | | getMinuteCapitalFlow | throws | Missing payload → [] | | getDailyCapitalFlow | throws | Missing payload → [] | | getMarginFinancingRecords | throws | Missing payload → [] | | getDividendRecords | throws | No stock/fund rows → [] |

Network / HTTP failures from fetcher generally throw.


Facade API (recommended)

These are the primary entry points. Prefer them over low-level build* / parse* helpers.

getKlineBars(code, options?)

OHLCV bars with vendor fallback.

| Option | Type | Default | Description | |---|---|---|---| | frequency | '1d' \| '1w' \| '1M' \| '1m' \| '5m' \| '15m' \| '30m' \| '60m' | '1d' | Bar interval | | count | number | 10 | How many bars to request (upstream day bars ~1000 max) | | endDate | string | '' | Used by Tencent day fallback | | fetcher | Fetcher | fetch | Custom HTTP client |

Source strategy

| Frequency | Primary | Fallback | |---|---|---| | 1d / 1w / 1M | Sina (vendor default) | Tencent fqkline (qfq 前复权) | | 1m | Tencent | — | | 5m / 15m / 30m / 60m | Sina | Tencent minute |

Returns Promise<KlineBar[]>

type KlineBar = {
  time: string;   // e.g. "2026-05-13" or "2026-05-13 10:00"
  open: number;
  high: number;
  low: number;
  close: number;
  volume: number;
};
import { getKlineBars } from 'cn-market-data';

const bars = await getKlineBars('sh601398', { frequency: '1d', count: 120 });
console.log(bars.at(-1));

getOrderBook(code, options?)

Five-level order book.

| Option | Type | Default | |---|---|---| | fetcher | Fetcher | fetch |

Source: Tencent → Baidu fallback. Throws if neither has data.

Returns Promise<StockOrderBook>

type StockOrderBook = {
  code: string;
  shortName: string;
  asks: OrderBookLevel[]; // sell 1 → sell 5
  bids: OrderBookLevel[]; // buy 1 → buy 5
};

type OrderBookLevel = {
  level: number;  // 1 = best
  price: number;  // yuan
  volume: number; // shares
};
import { getOrderBook } from 'cn-market-data';

const book = await getOrderBook('sh600519');
console.log(book.bids[0], book.asks[0]);

getTradeTicks(code, options?)

Recent trade ticks.

| Option | Type | Default | |---|---|---| | limit | number | 60 | | fetcher | Fetcher | fetch |

Source: Baidu → Tencent fallback.

Returns Promise<StockTradeTick[]> (latest limit ticks)

type StockTradeTick = {
  code: string;
  tradeTime: string; // Baidu: "YYYY-MM-DD HH:mm:ss"; Tencent fallback may be "HH:mm:ss"
  price: number;
  volume: number;
  bsType: string;    // e.g. "B" / "S" or vendor code
};
import { getTradeTicks } from 'cn-market-data';

const ticks = await getTradeTicks('sz000001', { limit: 20 });

getMinuteCapitalFlow(code, options?)

Intraday capital-flow points (East Money).

| Option | Type | Default | |---|---|---| | limit | number | 60 | | fetcher | Fetcher | fetch |

Returns Promise<CapitalFlowPoint[]>

type CapitalFlowPoint = {
  code: string;
  tradeTime: string;      // usually "YYYY-MM-DD HH:mm"
  mainNetInflow: number;  // yuan
  smallNetInflow: number;
  mediumNetInflow: number;
  largeNetInflow: number;
  maxNetInflow: number;   // 超大单
};

getDailyCapitalFlow(code, options?)

Daily capital-flow history (East Money).

| Option | Type | Default | |---|---|---| | limit | number | 30 | | startDate | string | — | Inclusive filter YYYY-MM-DD | | endDate | string | — | Inclusive filter YYYY-MM-DD | | fetcher | Fetcher | fetch |

Returns Promise<DailyCapitalFlowPoint[]>

type DailyCapitalFlowPoint = {
  code: string;
  tradeDate: string; // YYYY-MM-DD
  mainNetInflow: number;
  smallNetInflow: number;
  mediumNetInflow: number;
  largeNetInflow: number;
  maxNetInflow: number;
};
import { getDailyCapitalFlow } from 'cn-market-data';

const flow = await getDailyCapitalFlow('sh600519', {
  startDate: '2025-01-01',
  endDate: '2025-12-31',
  limit: 250,
});

getMarginFinancingRecords(code, options?)

Margin financing / securities lending daily series (East Money).

| Option | Type | Default | |---|---|---| | limit | number | 7 | | fetcher | Fetcher | fetch |

Returns Promise<StockMarginFinancingRecord[]>

type StockMarginFinancingRecord = {
  code: string;
  rawCode: string;          // e.g. "600519"
  name: string;
  secuCode: string;         // e.g. "600519.SH"
  tradeDate: string;        // YYYY-MM-DD
  financingBalance?: number;
  financingBuyAmount?: number;
  financingRepayAmount?: number;
  financingNetBuyAmount?: number;
  financingBalanceRatio?: number;       // %
  securitiesLendingVolume?: number;
  securitiesLendingBalance?: number;
  securitiesLendingSellVolume?: number;
  securitiesLendingRepayVolume?: number;
  securitiesLendingNetSellVolume?: number;
  marginBalance?: number;
  closePrice?: number;
  changePct?: number;
  circulatingMarketValue?: number;
  financingBalanceGrowthRate?: number;
};
import { getMarginFinancingRecords } from 'cn-market-data';

const rows = await getMarginFinancingRecords('sh600519', { limit: 30 });

getDividendRecords(code)

Cash dividend history for stocks and ETFs (East Money).

Lookup order

  1. Stock share-bonus report (RPT_SHAREBONUS_DET)
  2. If empty → fund/ETF dividend report (RPT_F10_FUND_DIVIDEND)

Returns Promise<StockDividendRecord[]>

type StockDividendRecord = {
  code: string;
  reportDate: string;                 // announcement date YYYY-MM-DD
  dividendPlan: string;               // vendor text, e.g. "10派1.689元(含税,扣税后1.5201元)"
  exDividendDate: string | null;      // 除权除息日
  cashDividendPerShare: number | null; // 含税,元/股 or 元/份
};

Cash math (broker pre-tax)

到账含税现金 ≈ 持仓数量 × cashDividendPerShare
  • Stocks: cashDividendPerShare = PRETAX_BONUS_RMB / 10(每 10 股派息 → 每股)
  • ETFs: cashDividendPerShare = DIVIDEND(每份)
  • Personal dividend tax is not applied here (depends on holding period; often settled when selling)
import { getDividendRecords } from 'cn-market-data';

const icbc = await getDividendRecords('sh601398');
// e.g. cashDividendPerShare === 0.1689  →  1000 shares × 0.1689 = 168.9 yuan (pre-tax)

const etf = await getDividendRecords('sh515080');
// e.g. cashDividendPerShare === 0.02    →  10000 units × 0.02 = 200 yuan (pre-tax)

API overview

| Function | Data | Source | |---|---|---| | getKlineBars | OHLCV | Sina / Tencent | | getOrderBook | 五档盘口 | Tencent / Baidu | | getTradeTicks | 分笔成交 | Baidu / Tencent | | getMinuteCapitalFlow | 分钟资金流 | East Money | | getDailyCapitalFlow | 日资金流 | East Money | | getMarginFinancingRecords | 融资融券 | East Money | | getDividendRecords | 现金分红(股/ETF) | East Money |


Public surface

Only the Facade is published:

| Category | Exports | |---|---| | Methods | getKlineBars, getOrderBook, getTradeTicks, getMinuteCapitalFlow, getDailyCapitalFlow, getMarginFinancingRecords, getDividendRecords, assertMarketCode | | Options | RequestOptions, LimitOptions, GetKlineBarsOptions, GetDailyCapitalFlowOptions | | Types | Fetcher, Frequency, KlineBar, OrderBookLevel, StockOrderBook, StockTradeTick, CapitalFlowPoint, DailyCapitalFlowPoint, StockMarginFinancingRecord, StockDividendRecord |

Vendor build* / parse* helpers are not part of the public API (repo-internal only).


Custom fetcher (Cloudflare Workers / tests)

import { getKlineBars } from 'cn-market-data';

await getKlineBars('sh600519', {
  frequency: '1d',
  count: 30,
  fetcher: (input, init) => fetch(input, init),
});

Notes / limits

  • Day/week/month history depth is bounded by upstream APIs (~1000 bars).
  • Dividend precision for stocks follows East Money PRETAX_BONUS_RMB (e.g. ICBC 1.689 / 10 = 0.1689).
  • Hong Kong / overseas symbols are rejected by design.
  • Not financial advice; data is for engineering / research use.

License

MIT