一個開發來為使用者 個人記帳、長期投資管理用 的「個人投資可視化系統」專案,專門拿來快速管理自己的持股(目前以臺股為主)、資產配置,並檢視持股股價走勢、基本面摘要與新聞訊息,以及回測投資策略。 前端使用 Vue 3 + Vite + Pinia + D3.js + TailwindCSS,後端使用 Node.js + Express + SQLite 快取股價與基本面。
⚠️ 免責聲明:本專案僅供個人學習與技術實驗使用,所有資料與分析結果都不構成任何投資建議,投資前請衡量自身風險承受能力。
-
Dashboard 儀表板(大總覽)
- 持股總市值、今日損益、個人持股近 7 日漲跌幅、現金部位佔比。
- 各標的持股比重圖、股票近期趨勢圖(支援
1日/5日/30日/6個月/1年/5年/10年/最久等 Time Frame 切換)。 - 個人持倉明細、臺股上市公司市值佔比圖。
個人近期投資事件(功能開發中)。
-
Portfolio 持股管理
- 個人動產(股票 + 現金)總值、持股總成本、整體報酬率、現金比例。
- 資產分布圖、個人資產變化圖(支援
1週/1個月/1季/半年/1年/5年/最久等 Time Frame 切換)。 - 個人持股明細(可於此處編輯,將自動計算單檔市值與報酬率)。
- 目前會將資料存於
localStorage,重新整理頁面不會消失。
-
Stock Detail 個股詳細頁
- 從自建後端抓取 TWSE 日線資料,並提供價格走勢圖,預設公司為「臺灣市值第 1 大公司」。
- 支援
7D/1M/3M/1Y/3Y等 Time Frame 切換。 - 提供技術指標小卡:
MA(20)/MA(50)/RSI/Vol Avg。 - 提供基本面摘要:本益比(PE)、股價淨值比(PB)、殖利率、股本、估算之近四季 EPS。
- 個人該股持倉摘要:成本、持股數、損益與百分比。
- 一鍵搜尋 PTT / Dcard 該股票相關討論。
個人該股持有時間圖(功能開發中)。- 顯示相關新聞 / 消息。
-
Backtest 回測
- 多檔比較
- 提供不同個股或 ETF 之滾動報酬率視覺化比較,有
對數刻度/一般刻度供選擇。
- 提供不同個股或 ETF 之滾動報酬率視覺化比較,有
- 單檔比較
- 有「股票代號」、「起迄日期」、「初始資金」、「策略選擇」、「每次投入資金」等參數可設定。
- 投資策略選項有「單筆買入」、「定期定額」、「均線交叉」、「RSI 超買超賣」供選擇。
- 資產變化走勢圖,及 KPI 數據(區間總報酬率、最大回撤、年化報酬率、勝率)可參考。
- 多檔比較
-
Reports 報表管理
- 自訂報表區間、報表種類(總覽、持倉明細、
交易紀錄、空白報表)。 - 顯示上次產生報表標題與時間點、累計產生次數、預設內容、上次運行耗時等小卡。
- 報表預覽,提供匯出 CSV、JSON、PDF 文件 等功能做匯出選擇。
- 提供「最近幾筆的匯出紀錄」與「預設報表」供快速輸出。
- 有「報表匯入」的功能,符合格式的 JSON 檔或 CSV 檔可直接匯入。
- 自訂報表區間、報表種類(總覽、持倉明細、
-
Settings 顯示設定
- 個人化設定
- 個人名稱、電子信箱、貨幣單位、顯示位數千分位。
- 外觀主題(日間模式 / 夜間模式)。
推播通知(功能開發中)。- 匯出 / 匯入設定檔。
登出功能鍵(功能開發中)。
- 個人化設定
-
- 使用 Vue 3 Composition API 與 Vue SFC(單檔元件)開發,方便內容維護與擴充。
- 採用 Vite 作為建構工具,啟動快速、熱重載流暢。
-
Pinia - Store 狀態管理。
-
D3.js - 用於繪製資料視覺化圖表。
-
- 使用 Utility Class 設定樣式與佈局。
- 實作 RWD 響應式設計,手機、平板、桌機皆可順暢瀏覽。
-
jsPDF - 直接透過前端匯出 PDF 文件。
-
better-sqlite3 - 本地 SQLite 快取。
-
node-fetch - 呼叫外部 API。
-
cheerio - 解析 TAIFEX / TWSE HTML 表格。
-
iconv-lite - 將 Big5 頁面轉 UTF-8。
-
專案部署於 Railway,前端 build 之後,由 Node.js + SQLite 寫成的後端伺服器服務。
-
Demo 首次開啟可能因平台閒置機制而有短暫延遲,之後會因 SQLite / JSON 快取加速。
Live Demo: My Stock Map
-
TWSE 證交所
-
STOCK_DAY:日線歷史股價。 (https://www.twse.com.tw/exchangeReport/STOCK_DAY) -
BWIBBU:單檔本益比 / 股價淨值比 / 殖利率。 (https://www.twse.com.tw/exchangeReport/BWIBBU) -
BWIBBU_d:某日全市場本益比 / 股價淨值比 / 殖利率清單。 (https://www.twse.com.tw/exchangeReport/BWIBBU_d) -
t187ap03_L:股本(實收資本額) Open Data。 (https://openapi.twse.com.tw/v1/opendata/t187ap03_L) -
ISIN 上市 / 上櫃清單(HTML,含代碼、名稱、產業)。 (
https://isin.twse.com.tw/isin/C_public.jsp?strMode=2)(上市)
(https://isin.twse.com.tw/isin/C_public.jsp?strMode=4)(上櫃)
-
-
FinMind TaiwanStockInfo(代碼/名稱/產業/上市別,作為 ISIN 備援來源)
(https://api.finmindtrade.com/api/v4/data?dataset=TaiwanStockInfo) -
TAIFEX 期交所(台指 / 櫃買成分股、市值權重)
-
台指成分股比重:
https://www.taifex.com.tw/cht/9/futuresQADetail -
櫃買成分股比重:
https://www.bq888.taifex.com.tw/cht/2/tPEXPropertion
-
-
新聞來源
- GDELT Doc API:依股票名稱/代碼搜尋近期新聞標題
- Google News RSS:作為 GDELT 失敗時的備援新聞來源
my-stock-map/
|
├─src/
│
┌───┘
│
├─ pages/ ← 主要的 6 個頁面
│ ├─ Dashboard.vue ← 總覽 / 持股分布 / 持倉明細 / 大盤市值佔比
│ ├─ Portfolio.vue ← 資產分布 / 資產變化圖 / 持股明細
│ ├─ StockDetail.vue ← 個股詳情 / 價格走勢 / 基本面 / 新聞
│ ├─ Backtest.vue ← 多檔回測 / 單檔回測
│ ├─ Reports.vue ← 報表管理
│ └─ Settings.vue ← 個人化設定
│
├─ components/ ← 主要 6 頁面的元件
│ ├─ Common/
│ │ ├─ EditHoldingModal.vue ← 編輯持股明細的表格視窗(增、刪、調整持股用)
│ │ ├─ Footer.vue ← 頁尾 Footer
│ │ ├─ HeaderBar.vue ← 頂部導覽列 + 股票搜尋列 + 登入按鈕
│ │ ├─ LoadingModal.vue ← 全螢幕 Loading 覆蓋層(資料載入時顯示)
│ │ ├─ LogInPage.vue ← 登入對話框(Email / 密碼)
│ │ ├─ MyStockMapLogo.vue ← My Stock Map 的 Logo 元件檔
│ │ ├─ SideBarMenu.vue ← 側邊選單(切換頁面用)
│ │ └─ WelcomeModal.vue ← 歡迎視窗(進入網站時顯示)
│ ├─ Dashboard/
│ │ ├─ HoldingDetails.vue ← 持倉明細表格(Dashboard 版本)
│ │ ├─ MarketCapitalizationTreemap.vue ← 台股大盤市值佔比 Treemap 圖
│ │ ├─ PerformanceChart.vue ← 目前選定標的的歷史走勢折線圖
│ │ ├─ ShareholdingRatioChart.vue ← 持股分布甜甜圈圖(Dashboard 版本)
│ │ ├─ SummaryCards.vue ← Summary 卡片(Dashboard 版本)
│ │ └─ TimelineList.vue ← 最近投資事件列表
│ ├─ Portfolio/
│ │ ├─ HoldingDetails.vue ← 持股明細表格(Portfolio 版本)
│ │ ├─ PersonalAssetsChart.vue ← 個人總資產變化折線圖
│ │ ├─ ShareholdingRatioChart.vue ← 資產分布甜甜圈圖(Portfolio 版本)
│ │ └─ SummaryCards.vue ← Summary 卡片(Portfolio 版本)
│ ├─ StockDetail/
│ │ ├─ PriceChartCard/
│ │ │ └─ IndicatorSummaryCards.vue ← 技術指標小卡(MA20 / MA50 / RSI / 均量)
│ │ ├─ HoldingTimelineChart.vue ← 個人持有股數隨時間變化圖
│ │ ├─ InformationSummary.vue ← 基本面摘要 + 個人持倉摘要 + 外部論壇討論連結
│ │ ├─ PriceChartCard.vue ← 個股價格走勢圖
│ │ └─ RelevantNews.vue ← 相關新聞列表
│ ├─ Backtest/
│ │ ├─ SingleAssetsBacktest/
│ │ │ └─ SingleAssetsBacktestChart.vue ← 單檔回測資產淨值折線圖 + KPI 摘要小面板
│ │ ├─ RollingReturnTest.vue ← 多檔回測的滾動報酬率比較
│ │ └─ SingleAssetsBacktest.vue ← 單檔回測參數表單 + 策略選擇 + KPI 計算
│ ├─ Reports/
│ │ ├─ ExportAndPresetLists.vue ← 最近匯出列表 + 預設報表任務清單
│ │ ├─ HeaderAndControls.vue ← 報表管理頁標題 + 日期區間 / 模板選擇表單
│ │ ├─ ReportImport.vue ← 報表匯入區
│ │ ├─ ReportPreview.vue ← 報表預覽區
│ │ └─ SummaryCards.vue ← Summary 卡片(Reports 版本)
│ └─ Settings/
│
├─ store/
│ ├─ displayFormat.js ← 貨幣 / 百分比格式化(UI 顯示設定用)
│ ├─ portfolio.js ← 持股資料 + localStorage
│ ├─ queryStock.js ← 全站目前查詢的 symbol(目前選中的股票代碼)
│ ├─ settingItems.js ← 一般設定(顯示名稱 / Email / 貨幣單位 / 通知偏好)
│ ├─ theme.js ← 深淺色主題(Tailwind dark mode 切換)
│ └─ uiState.js ← 頁籤 / 主頁面切換
│
├─ api/
│ └─ stocksApi.js ← 與本地後端溝通的股票 API 工具(股價序列正規化 / 公司清單 / 基本面 / 新聞 + 前端快取)
│
├─ assets/
│ └─ vue.svg
│
├─ data/
│ └─ mock/
│ ├─ assetsMockData.js ← 個人總資產歷史假資料(活存餘額 + 每日持股市值)
│ ├─ marketCapitalizationTreemapDate.js ← 台股大盤市值佔比 Treemap 用假資料
│ ├─ mockData0050.js ← 0050 歷史 OHLC 假資料
│ ├─ mockData2330.js ← 2330 歷史 OHLC 假資料
│ ├─ mockData2412.js ← 2412 歷史 OHLC 假資料
│ ├─ mockData2881.js ← 2881 歷史 OHLC 假資料
│ ├─ mockDataCompanyName.js ← 台股代號與公司名稱對應清單假資料
│ └─ portfolioData.js ← 預設投資組合假資料(持股明細)
│
├─ App.vue ← Root 佈局:Header / 側邊選單 / 主內容 + data-theme 深淺色容器
├─ main.js ← Vue 進入點:建立 App、掛載 Pinia、載入全域樣式並掛載到 #app
└─ style.css ← Tailwind 入口 + 自訂 light/dark 主題 + 自訂 UI utility 類別
my-stock-map/
┌┘
│
├─ server/
│ ├─ index.js ← 主伺服器:建立 stocks.db 股價表,提供 /api/stocks + /api/news,並掛載 symbols / rankings / fundamentals 路由
│ ├─ symbolMap.js ← 抓 TWSE ISIN / FinMind 產生 symbols.json,並提供 /api/symbols* 代號/名稱查詢 API
│ ├─ rankings.js ← 抓 TAIFEX 權重表整理成市值排名,快取於 market_ranks.json 並提供 /api/market-ranks* API
│ └─ fundamentalDetails.js ← 向 TWSE 取單檔/全市場基本面 + 股本,結合 DB 最新收盤估算 EPS,提供 /api/fundamentals/:code
└─ data/
├─ stocks.db ← SQLite 股價快取資料庫(stock_prices 日 K 表)
├─ symbols.json ← symbolMap.js 產生的代號 / 名稱 / 上市別 / 產業 快取
└─ market_ranks.json ← rankings.js 產生的上市 / 上櫃市值排名快取
-
前端(例如
PriceChartCard.vue)呼叫api/stocksApi.js中的fetchStockSeries(symbol, params)函式。 -
api/stocksApi.js將請求轉發到後端/api/stocks/:symbol。 -
後端:
-
檢查
stocks.db是否已有該月份資料。 -
若無 → 打 TWSE
STOCK_DAYAPI 抓指定月份,寫入 SQLite。 -
未來同一檔、同一範圍就直接從 SQLite 回傳,不再打 TWSE。
-
-
fetchStockSeries()內部把後端回傳的原始 JSON 正規化成StockBar[](日期→Date,數字→number),用 D3.js 畫圖。 -
基本面
/api/fundamentals/:code同理,後端負責打 TWSE & open data,前端只拿整理好的結果。 -
新聞
/api/news/:code優先嘗試 GDELT → 失敗再用 Google News RSS,前端只渲染結果。
以下指令假設已經安裝好 Node.js 和 npm。
這個 repo 的目錄結構是:
my-stock-map/
┌┘
├─ data/ ← 後端產生的data
├─ public/
├─ server/ ← 後端伺服器
│ ├─ index.js
│ └─ ...
├─ src/ ← 前端 Vue 內容
├─ index.html
├─ package-lock.json
├─ package.json
├─ README.md
├─ vite.config.js
└─ ...
-
Clone 專案
git clone https://github.com/quanting56/my-stock-map.git cd my-stock-map -
安裝前端依賴(專案根目錄)
npm install
-
安裝後端依賴(server 子資料夾)
cd server npm install cd ..
建議接下來「開兩個終端視窗」:一個跑後端,一個跑前端。
-
啟動後端(Express + SQLite,在專案根目錄啟動 Terminal A)
node server/index.js # 開發環境中,後端伺服器預設跑在 http://localhost:3000 # 部署於 Railway 時,實際會使用平台提供的 PORT(目前為 8080)
-
啟動前端(Vite Dev Server,在專案根目錄啟動 Terminal B)
npm run dev # 預設跑在 http://localhost:5173
前端會透過 http://localhost:3000 呼叫各種 API(股票、symbols、fundamentals、news)。
-
股價快取 SQLite
- 檔案路徑:
data/stocks.db - 同一檔股票第二次之後查詢,會直接從 SQLite 讀取,只有缺月份才再打 TWSE API。
- 檔案路徑:
-
代號 / 公司名稱快取
- 檔案路徑:
data/symbols.json - 來源:TWSE ISIN 頁面 → 若失敗就改用 FinMind。
- 檔案路徑:
-
市值排名快取
- 檔案路徑:
data/market_ranks.json - 來源:TAIFEX 頁面,解析表格後搭配
symbols.json對上代碼。
- 檔案路徑:
-
個人持股資料
- 儲存在瀏覽器
localStorage(key:myStockMap_holdings,由portfolio.jsstore 管理)。
- 儲存在瀏覽器
這些元件會出現在不同頁面中,可重複利用。
-
components/Common/HeaderBar.vue- 全站頂部導覽列:顯示 My Stock Map Logo、提供股票搜尋框(支援「/」快捷鍵聚焦)、登入按鈕與深淺色主題切換。
-
components/Common/SideBarMenu.vue- 左側功能選單:依據
uiState.jsstore 的tabs資訊產生按鈕,並用來切換 Dashboard / Portfolio / StockDetail / Backtest / Reports / Settings 等主要頁面。
- 左側功能選單:依據
-
components/Common/Footer.vue- 頁尾區塊:顯示 Logo 與專案標語、贊助連結群組、作者聯絡 Email 與版權 / 免責說明文字。
-
components/Common/EditHoldingModal.vue- 編輯持股資料的彈出視窗:以表格方式一次調整多檔持股(代碼、名稱、股數、現價、成本),支援新增 / 刪除列,儲存時會更新
portfolioStore.holdingDetailsData並呼叫portfolioStore.recalcValues(),實際的持股資料持久化則由portfolio.jsstore 統一寫入localStorage。
- 編輯持股資料的彈出視窗:以表格方式一次調整多檔持股(代碼、名稱、股數、現價、成本),支援新增 / 刪除列,儲存時會更新
-
components/Common/LoadingModal.vue- 全螢幕 Loading 遮罩(使用
<Teleport>掛到<body>):顯示轉圈圈與自訂訊息,用於資料載入中的全局提示。 - 可在使用元件時,透過
props的方式將自訂文字傳進子元件顯示在文字部分。
- 全螢幕 Loading 遮罩(使用
-
components/Common/LogInPage.vue- 全螢幕登入對話框遮罩(使用
<Teleport>掛到<body>):- Email / 密碼輸入欄位。
- 點擊背景或按 Esc 可關閉。
- 目前登入行為為暫時的
alert("登入功能建置中"),之後將接後端認證。
- 全螢幕登入對話框遮罩(使用
-
components/Common/MyStockMapLogo.vue- 專案 Logo 的 SVG 元件:將
<svg>元件化,提供給 Header、Footer 等處重複使用,未來若要改 Logo 只需改這一處(網站 Favicon 需另外到public/中修改)。
- 專案 Logo 的 SVG 元件:將
-
components/Common/WelcomeModal.vue- 全螢幕歡迎視窗(使用
<Teleport>掛到<body>):進入網站時會看到的招呼語與介紹文字。 - 使用者若登入且設定個人顯示名字,將會在此處個人化顯示。
- 全螢幕歡迎視窗(使用
現正進行中
-
針對手機或平板使用者做 UI/UX 優化。
-
Dashboard 股票趨勢圖,新增可以多檔並列,並讓使用者自訂顯示檔數。
-
完成
components/StockDetail/HoldingTimelineChart.vue的持有時間軸(依實際交易紀錄畫線)。 -
完成 Footer 的超連結與其頁面。
-
統一按鈕樣式。
-
改善 Stock Detail 頁面「價格走勢圖」的 tooltip 互動效果。
-
Portfolio 「個人資產變化趨勢圖」加上現金佔比圖。
-
Backtest 加入是否開啟「通膨修正」選項。
-
重新調整整體網站配色。
-
Dashboard 頁面的大盤市值佔比圖加上上櫃公司,使其能夠在上市公司與上櫃公司間做切換。
-
Portfolio 加上個人資產
週K/月K/季K/年K的 Candlestick Chart 區域。 -
調整 Dashboard 區塊,將
SummaryCards區域的「持股總市值」和「今日損益」放到持倉明細區域,原處改為最新加權指數與最新加權損益。 -
新增 Dashboard 大盤市值佔比圖焦點功能,當點擊 Dashboard 頁面其他含股票內容時,佔比圖中對應公司會自動高亮(若存在的話)。
近期規劃中
-
Portfolio 與 Stock Detail 串接實際持股成本,而不是 mock 值。
- 需要先決定「交易紀錄」資料結構(ex: [{date, id, action, qty, price}]),
- 再在前端或後端計算成交加總 &現有持股。
- JavaScript、Pinia、SQLite,只是多一層資料設計 + 邏輯而已。
-
調整 Dashboard 頁面小卡資料串接。
-
調整 Portfolio 頁面小卡資料串接。
-
完成 Reports 頁面中,報表匯入按鈕功能(模板編輯器遮罩)。
-
串連即時股價 API。
-
將 News 來源白名單設定改為可調整的狀態(加在 Settings 頁面),讓使用者可以自由選擇。
-
Stock Detail 頁面「個人持倉快速摘要」資料串接。
-
Stock Detail 頁面新增滾動最大回撤圖表。
-
新增「槓桿模擬」功能,參考 testfol.io 的
L、E、SW、SP參數設計:- 以原始標的 + 槓桿倍率
L+ 費用率E+ swap 比例SW+ 利率點差SP生成虛擬槓桿資產。 - 設計支援類似
2330SIM?L=2&E=0.95這種語法,對個股 / 指數做槓桿回測。
- 以原始標的 + 槓桿倍率
-
為仍在規劃中的指數 / ETF 設計「模擬資產代碼(SIM)」格式,類似 testfol.io 的
SPYSIM/QQQSIM方法:- 例:
0050SIM、TWII_SIM,用歷史成分股 + 權重來回推上市前的走勢。
- 例:
-
新增美股數據 / 資料。
-
將大盤公司依產業等類別及其子類別,照市值畫成 Sequences Sunburst。
-
在 Welcome Modal 上面增加文字雲 Word Cloud。
-
按照公司市值、產業市值、年份繪出 Animated Treemap。
-
製作 Idle Modal。
中長期規劃
-
改善後端程式碼架構,將
server/index.js依功能拆分。 -
完成 登入 / 登出 功能。
- 需要補的一些知識:
- Node.js + Express.js
- 密碼雜湊(bcrypt)
- Session 或 JWT
- 基本的「註冊 / 登入 / 驗證 middleware」
- 需要補的一些知識:
-
與其他使用者的投資競賽(目前投資報酬率相較於於整個專案使用者裡之排名)。
- 需要補的一些知識:
- SQLite + Node.js
- 需要處理:
- 使用者資料表 server-side data。
- 每個 user 的 portfolio / 交易紀錄。
- 定期計算報酬率並排行。
- 需要補的一些知識:
-
推播功能(預計於 App 化後進行)
- 需要補的一些知識:
- PWA 基礎。
- Swift / Kotlin / Flutter / React Native。
- 需要補的一些知識:
-
Stock Detail 中做「估值 / 殖利率 軌跡圖」
- 使用工具
- 連結散點圖 Connected Scatterplot
- 內容
- x 軸:股價淨值比 (P/B) 或 本益比 (P/E)
- y 軸:殖利率 (Dividend Yield)
- 每一個點:某個月 或 某年
- 使用工具
| 類型 | 用途說明 |
|---|---|
feat |
💡 新增功能(feature) |
fix |
🐛 修復錯誤(bug) |
docs |
📚 修改文件(README、說明文字、註解等) |
perf |
🚀 性能優化 |
refactor |
🔧 重構程式碼(邏輯不變,非 bug fix 或新功能) |
style |
🎨 調整程式碼格式(例如空格、縮排、換行,不影響功能) |
test |
✅ 增加或修改測試內容 |
build |
🏗️ 編譯相關檔案變動,如 Vite 設定或打包流程 |
revert |
⏪ 撤銷回覆先前的commit |
chore |
🔨 其他雜項(部署設定、更新套件、CI 設定、建置腳本等) |
本案由 quanting56 開發與維護。
README.md 更新時間:2025/12/12 23:09