我用 stock-sdk 构建了一个个人专属的 A 股行情仪表盘
写给前端的股票行情 SDK: stock-sdk,终于不用再求后端帮忙了
用 JavaScript 获取股票数据,真的有这么难吗?
起因
说实话,这个项目的诞生完全是被逼出来的。
去年我想做一个股票行情看板,就是那种简单的页面,能实时显示几只自选股的涨跌。听起来很简单对吧?但当我真正开始动手的时候,才发现事情没那么简单。
网上搜一圈,股票数据接口相关的工具几乎全是 Python 的。AkShare、Tushare、掘金量化……确实牛,功能也确实全,但问题是——我是个前端啊。
为了一个小看板,难道要我专门搭一个 Python 后端?再写个接口转发给前端?这也太折腾了。
于是我开始找有没有 JavaScript 能用的方案。结果你猜怎么着?翻遍了 npm,几乎找不到一个好用的。有的年久失修,有的只支持 Node.js 不支持浏览器,有的类型支持一塌糊涂,还有的接口莫名其妙就挂了。
摸索了一圈之后,我决定:算了,自己写一个得了。
stock-sdk 是什么?
简单说,stock-sdk 就是一个专门给前端和 Node.js 用的股票行情 SDK。
核心目标就一个:让你用最熟悉的 JavaScript / TypeScript,10 行代码搞定股票数据获取。
import { StockSDK } from 'stock-sdk';
const sdk = new StockSDK();
const quotes = await sdk.getSimpleQuotes(['sh000001', 'sz000858', 'sh600519']);
quotes.forEach(q => {
console.log(`${q.name}: ${q.price} (${q.changePercent}%)`);
});
就这么简单。不用搭后端,不用装 Python,浏览器里直接跑。
它能干什么?
写到现在,功能已经比较齐全了:
行情数据
- A 股、港股、美股、公募基金的实时行情
- 历史 K 线(日线、周线、月线)
- 分钟 K 线(1 分钟到 60 分钟都支持)
- 当日分时走势
板块数据
- 行业板块、概念板块的列表和实时行情
- 板块成分股
- 板块 K 线数据
技术指标
- 内置 MA、MACD、BOLL、KDJ、RSI 等常用指标
- 一个接口搞定 K 线 + 指标计算
扩展数据
- 资金流向
- 盘口大单
- A 股交易日历
批量能力
- 一次性获取全市场 5000+ 只 A 股行情
- 内置并发控制,不会把接口打挂
- 进度回调,知道当前拉取到哪里了
为什么要用它?
说实话,这个问题我自己也想过很久。毕竟市面上不是没有其他方案。
但仔细想想,stock-sdk 确实解决了一些痛点:
1. 零依赖,真的很小
压缩后不到 20KB。没有乱七八糟的依赖,不会给你的项目增加额外负担。
2. 浏览器和 Node.js 都能跑
这个是我一开始就确定的设计目标。不管你是做 Web 页面还是 Node.js 脚本,都能直接用。同时提供 ESM 和 CommonJS 两种格式,现代项目和老项目都兼容。
3. TypeScript 类型完整
说真的,类型提示这个东西,用过就回不去了。每个接口返回什么字段、每个参数是什么类型,IDE 里一目了然。写代码的时候不用反复查文档。
4. 接口稳定
数据源用的是腾讯财经和东方财富的公开接口,稳定性还是有保障的。而且我做了比较完善的错误处理,不会因为某个请求失败就整个崩掉。
适合什么场景?
这个 SDK 不是万能的,我也不打算把它做成大而全的东西。它比较适合这些场景:
- 股票看板:做一个自选股页面,看看涨跌
- 数据可视化:用 ECharts 或者 TradingView 画 K 线图
- 学习 Demo:金融课程、量化入门的演示项目
- 量化验证:快速验证一个交易策略的想法
- 定时脚本:Node.js 定时抓取行情数据
如果你需要更专业的量化回测、高频交易之类的,这个 SDK 可能就不太够用了。那种场景还是 Python 生态更成熟。
一些实际的例子
获取全市场 A 股行情
const allQuotes = await sdk.getAllAShareQuotes({
batchSize: 300,
concurrency: 5,
onProgress: (completed, total) => {
console.log(`进度: ${completed}/${total}`);
},
});
console.log(`共获取 ${allQuotes.length} 只股票`);
5000 多只股票,几秒钟就拉完了。并发控制是内置的,不用自己操心。
获取带技术指标的 K 线
const data = await sdk.getKlineWithIndicators('sh600519', {
period: 'daily',
count: 100,
indicators: {
ma: { periods: [5, 10, 20] },
macd: true,
boll: true,
},
});
// data.kline 是原始 K 线
// data.indicators.ma 是均线数据
// data.indicators.macd 是 MACD 数据
// data.indicators.boll 是布林带数据
一个接口把 K 线和指标都算好了,直接拿去画图就行。
写在最后
这个项目从去年开始写,断断续续维护到现在,功能也越来越完善了。
其实我一直觉得,工具这个东西,好不好用自己最清楚。stock-sdk 就是我自己在用的东西,遇到问题就修,需要新功能就加。
如果你也是前端,也需要获取股票数据,不妨试试。有问题欢迎提 Issue,我会尽量响应。
相关链接
安装就一行命令:
npm install stock-sdk
如果觉得还不错,给个 Star ⭐ 呗~
这是个啥
背景故事很简单:作为一个日常关注行情的“韭菜”,我有一个不太高效的习惯——同时打开无数个看盘软件和网页,在混乱的窗口切换中迷失自我,最终收获的往往只有焦虑,外加浏览器那令人窒息的标签页堆叠。为了彻底治愈这种低效,我决定动手打造一个专属工具:在一个页面内集成所有高频功能,涵盖实时行情、板块动态、分时走势、K 线分析、资金流向以及筛选器。
这就诞生了 stock-dashboard:一个完全基于 React + TypeScript + Vite 技术栈的前端大屏。所有数据直接由 stock-sdk 驱动,这意味着项目完全摒弃了后端服务,不需要运行任何 Python 定时任务,也不依赖什么“神秘朋友的高端服务器”。纯前端直连数据源,所见即所得,一切都安排得井井有条。
直接上在线演示链接:stock-dashboard (友情提示:摸鱼期间请谨慎使用,建议配合小窗口模式)。
核心解密:数据层架构设计
为了保持代码整洁,我将所有针对 stock-sdk 的调用逻辑都封装在了 src/services/sdk.ts 中。
这里主要实施了三个既实用又不矫情的工程化策略:
-
全局单例与自动重试机制
通过new StockSDK({ timeout, retry })初始化实例。面对网络波动或接口偶尔抽风的情况,SDK 内置的自动重试机制(支持最大 3 次重试及指数退避算法)能完美兜底。 -
智能内存缓存(TTL 策略)
对于行业或概念列表这类变动频率极低的数据(毕竟它们不会在几秒内发生剧变),直接上缓存减少无效请求;而对于实时行情,则设置了 2~3 秒的生存期(TTL),既保证了数据的时效性,又避免了无意义的高频请求轰炸接口。 -
分层隔离:页面仅对接服务层
翻阅src/pages/**下的代码,你几乎找不到new StockSDK()的身影。UI 层只负责调用诸如getFullQuotes / getTodayTimeline / getKlineWithIndicators等经过二次封装的业务方法,而类型定义则直接复用stock-sdk的导出。
顺便展示两段核心代码骨架,后续的所有功能模块皆构建于此基础之上:
// src/services/sdk.ts
export const sdk = new StockSDK({ timeout: 30000, retry: { maxRetries: 3, baseDelay: 1000, maxDelay: 10000, backoffMultiplier: 2 } });
export async function getFullQuotes(codes: string[], useCache = true) {
const key = getCacheKey('getFullQuotes', codes);
if (useCache) {
return withCache(key, DEFAULT_TTL.quotes, () => sdk.getFullQuotes(codes));
}
return sdk.getFullQuotes(codes);
}
// src/services/sdk.ts
export async function getAllAShareQuotes(options?: { batchSize?: number; concurrency?: number; onProgress?: (completed: number, total: number) => void }) {
return sdk.getAllAShareQuotes(options);
}
功能拆解:各模块如何玩转 stock-sdk 数据?
路由配置位于 src/router/index.tsx,而各个功能页面则模块化地分布在 src/pages/* 目录下。接下也就是大家最关心的——按“用户交互路径”来逐一复盘。
1) 全局搜索:告别手动翻代码的痛苦
搜索栏组件位于 src/components/layout/Header.tsx,其背后的魔法仅需一行代码:
search(keyword)映射到stock-sdk的sdk.search(keyword)
为了优化体验,我添加了 300ms 的输入防抖处理。搜索结果完美支持个股与板块的混合查询,点击即达:
- 行业板块跳转至:
/boards/industry/:code - 概念板块跳转至:
/boards/concept/:code - 个股详情跳转至:
/s/:code
顺手还利用 localStorage 实现了一个简单的历史记录功能(src/services/storage.ts),毕竟很多时候,我们寻找的不是新标的,而是昨天没看完的那个它。
2) 仪表盘 Dashboard:行情概览与自选速览
对应页面文件:src/pages/Dashboard/Dashboard.tsx。
数据获取逻辑非常直白粗暴:
- 指数行情:调用
getFullQuotes(MAIN_INDICES)一次性获取上证、深成指、科创 50 等关键指数。 - 板块概况:并行调用
getIndustryList()和getConceptList()。 - 自选股预览:先从存储服务
src/services/storage.ts读取自选列表,再通过getFullQuotes(watchlistCodes.slice(0, 50))批量获取前 50 只行情的快照。
为了保证数据的鲜活度,配合 usePolling Hook(src/hooks/usePolling.ts)实现了每 5 秒自动轮询。贴心的是,当页面处于后台不可见状态时,轮询会自动挂起,绝不浪费你的浏览器资源。
额外提一句:目前 Dashboard 上的“榜单”主要展示板块数据。如果想做全市场的个股排名,技术路径完全可以参考后面提到的“一日持股法”,也就是直接利用 getAllAShareQuotes 接口。
3) 市场热力图 Heatmap:一图看懂资金流向

实现文件位于 src/pages/Heatmap/Heatmap.tsx,底层依赖 ECharts 的矩形树图(Treemap)。
根据观察视角的不同,数据源也各异:
- 行业视角:直接用
getIndustryList(),因为返回的数据中已经包含了涨跌幅、换手率及领涨股信息。 - 概念视角:同理,调用
getConceptList()。 - 自选视角:获取所有自选代码
getAllWatchlistCodes()后,通过getAllQuotesByCodes(codes.slice(0, topK))批量拉取。
至于“全市场个股”热力图(代码预留了接口,暂未开启),实现逻辑也不复杂:
- 通过
getIndustryConstituents(industryCode)获取特定板块成分股。 - 用
getAllQuotesByCodes(stockCodes)把行情数据补齐。 - 最后组装数据喂给 Treemap 组件。
热力图最大的魅力在于:告别枯燥的数字列表,红绿相间的色块让你瞬间洞察市场强弱结构。
4) 龙虎榜 Rankings:观察市场风向标

页面路径:src/pages/Rankings/Rankings.tsx。
实现方式属于“简单粗暴且有效”:
- 并行获取
getIndustryList()和getConceptList()。 - 前端直接根据
changePercent(涨跌幅)或turnoverRate(换手率)进行排序,截取 Top 50。
目前的榜单本质上是“板块排行榜”。如果未来要扩展到全市场个股排行,技术方案与后文的“选股器”一致。
5) 板块透视:追踪领涨先锋
板块列表页位于 src/pages/Boards/Boards.tsx:
getIndustryList()与getConceptList()一把梭。- 所谓的 Tab 切换,仅仅是前端对不同数据源数组的渲染切换。
- 当然也支持按板块名称或领涨股进行检索。
详情页见 src/pages/Boards/BoardDetail.tsx,这里展示了 API 的组合拳能力(按行业/概念分流):
- 基础信息:直接复用列表数据,减少一次网络请求。
- 成分股列表:调用
getIndustryConstituents(code)或getConceptConstituents(code)。 - 板块走势:拉取
getIndustryKline或getConceptKline。 - 盘口快照:通过
getIndustrySpot或getConceptSpot获取。
为了保证流畅度,板块 K 线图目前只截取了最近 60 根数据,防止缩放图表时浏览器渲染压力过大。
6) 自选监控 Watchlist:只看我在意的
核心页面:src/pages/Watchlist/Watchlist.tsx。所有的增删改查逻辑都封装在 src/services/storage.ts 中。
行情刷新主要依赖:
getAllQuotesByCodes(normalizedActiveCodes)
特别提一下这里的细节处理:在请求前我会先通过 normalizeStockCode(位于 src/utils/format.ts)对代码进行标准化格式化,有效防止了 SZ000001、sz000001 和 000001 这种“一码多式”造成的去重失败或数据请求异常。
7) 个股深度分析 StockDetail:全维数据一览无余

页面位置:src/pages/StockDetail/StockDetail.tsx。这是整个项目中承载信息量最大的页面,因为它聚合了极高密度的信息。
它聚合了多维度的 API 数据:
- 实时报价:
getFullQuotes([code]) - 当日分时图(1分钟级):
getTodayTimeline(code) - 分钟级 K 线(5/15/30/60):
getMinuteKline(code, { period }) - 历史 K 线(日/周/月)及复权:
getKlineWithIndicators(code, { period, adjust: 'qfq', indicators }) - 资金流向监测:
getFundFlow([code]) - 盘口大单监控:
getPanelLargeOrder([code])
我个人非常推崇 getKlineWithIndicators 这个接口:只需传入你想要的指标参数(如 MA, MACD, KDJ, RSI, BOLL等),SDK 就能把计算好的指标数据连同 K 线一起返回。前端只需负责绘图,彻底告别了在前端手写复杂技术指标计算逻辑的噩梦(少写代码 = 少出 Bug = 长命百岁)。
在这里,轮询策略也做了精细化分层:
- 基础行情:2 秒/次
- 分时图:3 秒/次
- 资金流向:10 秒/次
8) 策略扫描器 Scanner:量化交易的初体验
页面:src/pages/Scanner/Scanner.tsx。
扫描逻辑简述如下:
- 确定股票池:
- 既可以是你的“自选股列表”。
- 也可以是某个板块的成分股,例如调用
getIndustryConstituents('BK0475')。
- 批量分析:
- 遍历每只股票,调用
getKlineWithIndicators获取带指标的 K 线数据。
- 遍历每只股票,调用
- 信号匹配:
- 前端逻辑判断最近两根 K 线是否满足预设形态(如均线金叉、MACD 金叉、RSI 超买超卖等)。
虽然这个功能带有一定的“心里安慰”属性,但它确确实实把模糊的“看涨感觉”转化为了可执行的“触发条件”。
9) 个性化设置 Settings:打造顺手的工具

页面:src/pages/Settings/Settings.tsx。
这个页面并没有调用任何 stock-sdk 接口,它的使命是将你的使用偏好(刷新频率、红涨绿跌配色、各类指标的默认参数等)持久化保存到 localStorage。这样,无论何时打开页面,它都还是那个你最熟悉的样子。
重头戏:一日持股策略(尾盘选股)——前端实现的全市场扫描

该功能位于 src/pages/EndOfDayPicker/EndOfDayPicker.tsx。我在这个页面实现了一套经典的“三步走”选股漏斗,其核心动力源自强大的 getAllAShareQuotes 接口。
第一阶段:全量 A 股行情抓取
// src/pages/EndOfDayPicker/EndOfDayPicker.tsx
const quotes = await getAllAShareQuotes({
batchSize: 500,
concurrency: 5,
onProgress: (completed, total) => setLoadingProgress({ completed, total, stage: '数据加载中...' }),
});
这一步调用的是 SDK 的重磅接口:
sdk.getAllAShareQuotes(options?: GetAllAShareQuotesOptions): Promise<FullQuote[]>- 参数
batchSize控制单次批大小(默认 500),concurrency控制并发数(默认 7)。
我采取了相对稳健的策略(并发设为 5),兼顾了浏览器的性能负载和网络稳定性。配合 onProgress 回调,用户能看到实时的进度条反馈,体验流畅不卡顿,不会误以为网页卡死。
第二阶段:基础指标粗筛
拿到全市场 5000+ 只股票的 FullQuote 数据后,我们先进行一轮粗筛(字段直接取自 FullQuote):
- 流通市值 (
circulatingMarketCap) - 量比 (
volumeRatio) - 涨跌幅 (
changePercent) - 换手率 (
turnoverRate) - ST/风险股过滤
这一步逻辑封装在 filterStocksBasic() 中,通常能把目标池从 5000+ 缩减到几百甚至几十只,如果不筛这一刀,后续拉取分时数据会直接把浏览器送走。
第三阶段:分时图形态精选
对于粗筛剩下的候选股,我们再进行更细致的分时图分析:
- 调用
getTodayTimeline(fullCode)拉取分时数据(注意拼接 sh/sz/bj 前缀)。 - 计算核心强度指标:
timelineAboveAvgRatio(即:现价高于均价的时间占比,由price和avgPrice对比得出)。
为了防止浏览器崩溃,filterWithTimeline() 中手动控制了分时数据请求的并发量(batchSize = 5)。
最终结果按 timelineAboveAvgRatio 降序排列,并在列表中展示迷你的分时走势图。这样一来,尾盘选股的效率直接起飞。
写在最后:谁需要这个工具?
如果你渴望拥有一个“既能看盘、又能筛股、还能顺便管理自选”的轻量级看板,同时极其排斥维护后端服务或编写复杂的 Python 脚本,那么这个纯前端方案绝对是你的不二之选。核心思路就是利用 stock-sdk 将强大的数据能力引入前端,剩下的就是单纯的 UI 组装与逻辑编排。
本地启动非常简单:
yarn install
yarn dev
最后不得不俗套地提醒一句:页面底部的 disclaimer “仅供学习参考,不构成投资建议”并非摆设。代码虽可自信敲,投资仍需谨慎行。
传送门
- 在线看板: https://chengzuopeng.github.io/stock-dashboard/
- SDK 文档: https://stock-sdk.linkdiary.cn/
- SDK 演练场: https://stock-sdk.linkdiary.cn/playground/

浙公网安备 33010602011771号