我用 stock-sdk 构建了一个个人专属的 A 股行情仪表盘
这是个啥
背景故事很简单:作为一个日常关注行情的“韭菜”,我有一个不太高效的习惯——同时打开无数个看盘软件和网页,在混乱的窗口切换中迷失自我,最终收获的往往只有焦虑,外加浏览器那令人窒息的标签页堆叠。为了彻底治愈这种低效,我决定动手打造一个专属工具:在一个页面内集成所有高频功能,涵盖实时行情、板块动态、分时走势、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 “仅供学习参考,不构成投资建议”并非摆设。代码虽可自信敲,投资仍需谨慎行。

这篇博客介绍了我用 stock-sdk 搭建的 A 股股票看板 stock-dashboard:基于 React + TypeScript + Vite 的纯前端项目,不依赖后端或定时脚本,直接在页面侧拉取行情并完成展示与筛选。文章从数据层封装(SDK 单例、重试、TTL 缓存、服务层统一出口)讲起,再按功能拆解搜索、Dashboard、热力图、板块/个股详情、自选、信号扫描与设置等模块。最后重点分享“一日持股法(尾盘选股)”的全市场扫描思路:先批量拉取 5000+ 行情做基础过滤,再分批拉分时计算强度指标并排序输出候选。
浙公网安备 33010602011771号