博客 / 詳情

返回

我用 stock-sdk 構建了一個個人專屬的 A 股行情儀表盤

這是個啥

背景故事很簡單:作為一個日常關注行情的“韭菜”,我有一個不太高效的習慣——同時打開無數個看盤軟件和網頁,在混亂的窗口切換中迷失自我,最終收穫的往往只有焦慮,外加瀏覽器那令人窒息的標籤頁堆疊。為了徹底治癒這種低效,我決定動手打造一個專屬工具:在一個頁面內集成所有高頻功能,涵蓋實時行情、板塊動態、分時走勢、K 線分析、資金流向以及篩選器

這就誕生了 stock-dashboard:一個完全基於 React + TypeScript + Vite 技術棧的前端大屏。所有數據直接由 stock-sdk 驅動,這意味着項目完全摒棄了後端服務,不需要運行任何 Python 定時任務,也不依賴什麼“神秘朋友的高端服務器”。純前端直連數據源,所見即所得,一切都安排得井井有條。

直接上在線演示鏈接:stock-dashboard (友情提示:摸魚期間請謹慎使用,建議配合小窗口模式)。
stock-overview

核心解密:數據層架構設計

為了保持代碼整潔,我將所有針對 stock-sdk 的調用邏輯都封裝在了 src/services/sdk.ts 中。

這裏主要實施了三個既實用又不矯情的工程化策略:

  1. 全局單例與自動重試機制
    通過 new StockSDK({ timeout, retry }) 初始化實例。面對網絡波動或接口偶爾抽風的情況,SDK 內置的自動重試機制(支持最大 3 次重試及指數退避算法)能完美兜底。

  2. 智能內存緩存(TTL 策略)
    對於行業或概念列表這類變動頻率極低的數據(畢竟它們不會在幾秒內發生劇變),直接上緩存減少無效請求;而對於實時行情,則設置了 2~3 秒的生存期(TTL),既保證了數據的時效性,又避免了無意義的高頻請求轟炸接口。

  3. 分層隔離:頁面僅對接服務層
    翻閲 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-sdksdk.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:一圖看懂資金流向

stock-heatmap

實現文件位於 src/pages/Heatmap/Heatmap.tsx,底層依賴 ECharts 的矩形樹圖(Treemap)。

根據觀察視角的不同,數據源也各異:

  • 行業視角:直接用 getIndustryList(),因為返回的數據中已經包含了漲跌幅、換手率及領漲股信息。
  • 概念視角:同理,調用 getConceptList()
  • 自選視角:獲取所有自選代碼 getAllWatchlistCodes() 後,通過 getAllQuotesByCodes(codes.slice(0, topK)) 批量拉取。

至於“全市場個股”熱力圖(代碼預留了接口,暫未開啓),實現邏輯也不復雜:

  1. 通過 getIndustryConstituents(industryCode) 獲取特定板塊成分股。
  2. getAllQuotesByCodes(stockCodes) 把行情數據補齊。
  3. 最後組裝數據餵給 Treemap 組件。

熱力圖最大的魅力在於:告別枯燥的數字列表,紅綠相間的色塊讓你瞬間洞察市場強弱結構。


4) 龍虎榜 Rankings:觀察市場風向標

stock-leaderboard

頁面路徑: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)
  • 板塊走勢:拉取 getIndustryKlinegetConceptKline
  • 盤口快照:通過 getIndustrySpotgetConceptSpot 獲取。

為了保證流暢度,板塊 K 線圖目前只截取了最近 60 根數據,防止縮放圖表時瀏覽器渲染壓力過大。


6) 自選監控 Watchlist:只看我在意的

核心頁面:src/pages/Watchlist/Watchlist.tsx。所有的增刪改查邏輯都封裝在 src/services/storage.ts 中。

行情刷新主要依賴:

  • getAllQuotesByCodes(normalizedActiveCodes)

特別提一下這裏的細節處理:在請求前我會先通過 normalizeStockCode(位於 src/utils/format.ts)對代碼進行標準化格式化,有效防止了 SZ000001sz000001000001 這種“一碼多式”造成的去重失敗或數據請求異常。


7) 個股深度分析 StockDetail:全維數據一覽無餘

stock-detail

頁面位置: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

掃描邏輯簡述如下:

  1. 確定股票池
    • 既可以是你的“自選股列表”。
    • 也可以是某個板塊的成分股,例如調用 getIndustryConstituents('BK0475')
  2. 批量分析
    • 遍歷每隻股票,調用 getKlineWithIndicators 獲取帶指標的 K 線數據。
  3. 信號匹配
    • 前端邏輯判斷最近兩根 K 線是否滿足預設形態(如均線金叉、MACD 金叉、RSI 超買超賣等)。

雖然這個功能帶有一定的“心裏安慰”屬性,但它確確實實把模糊的“看漲感覺”轉化為了可執行的“觸發條件”。


9) 個性化設置 Settings:打造順手的工具

stock-settings

頁面:src/pages/Settings/Settings.tsx

這個頁面並沒有調用任何 stock-sdk 接口,它的使命是將你的使用偏好(刷新頻率、紅漲綠跌配色、各類指標的默認參數等)持久化保存到 localStorage。這樣,無論何時打開頁面,它都還是那個你最熟悉的樣子。


重頭戲:一日持股策略(尾盤選股)——前端實現的全市場掃描

stock-last

該功能位於 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(即:現價高於均價的時間佔比,由 priceavgPrice 對比得出)。

為了防止瀏覽器崩潰,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/
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.