簡易股市查詢網

Andy Peng
9 min readJul 19, 2023

從AC畢業後是時候來做 side project 了,一直以來對股市都滿有興趣的就來做個簡易股市查詢網站吧 !

使用技術:

Template language: Handlebars
Frontend: Bootstrap, HTML, CSS, Javascript
Backend: Express.js
Database: Mysql
API: 臺灣證券交易所 OpenAPI, Yahoo Finance
Server: Heroku

重點功能:

今日大盤指數概覽:
快覽今日大盤各項指數漲跌情況,若漲跌百分比大於 2 %就會以紅字顯示

這頁其實滿簡單的基本上就是透過 axios 取得 openAPI 的大盤資料整理後呈現在網站上。

簡易選股策略:
提供 0050 / 0056 指數成分股與今日外資/投信買超股作為選股參考

這裡只放上外資/投信買超股是因為我個人只做多,另外由於證交網站資訊量比較大所以在查詢買賣超時會比較久。

個股查詢:
可透過輸入上市股票代號或是中文名稱進行搜索,會呈現該股票近 30 日的股價走勢圖,也可查看相關新聞。

關於個股則資料查詢是改用 Yahoo Finance API,主要原因是速度快,缺點是只能查到上市公司的股價且 ETF 股價整理資訊較慢常常會發生成分股最新股價已經出來但 ETF 則是呈現 null 的情況。
註: 台灣將上櫃股票獨立交由櫃買中心負責,因此若要查詢上市櫃資訊也是要用兩個 API 分別查詢

本頁的重頭戲就是K線圖,我是選用 chartjs 套件來畫圖,以下是官方文件提供的簡單長條圖示範,我把中文註解打在上面方便閱讀。
在這裡特別說明一下 options 的設定,在Y軸資料設定中 (data: [12, 19, 3, 5, 2, 3] )只有設定單一值的情況下 chartjs 也預設從 0 開始。

那到底K線要怎麼畫呢 ? 分別把開收價作為一組、最高最低價作為一組,再把兩個長條圖疊在一起看起來不就跟K線一樣了嗎 ?

<div>
<canvas id="myChart"></canvas>
</div>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

<script>
const ctx = document.getElementById('myChart'); // 先選定圖表位置

new Chart(ctx, {
type: 'bar', // 指定圖表類型
// 圖表設定
data: {
// X軸標籤(資料組名稱)設定
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
// Y軸資料設定
datasets: [{
label: '# of Votes', // Y軸標籤設定
data: [12, 19, 3, 5, 2, 3], // Y軸資料設定
borderWidth: 1 // 長條圖邊線寬度設定
}]
},
// 額外圖表設定(可選)
options: {
scales: {
y: {
beginAtZero: true // 指定圖表從0開始向上畫(資料最小值是0)
}
}
}
});
</script>
  const myChart = new Chart(ctx, {
type: "bar",
data: {
labels: date,
datasets: [
{
type: "bar",
backgroundColor: color, // 決定紅K或綠K
borderColor: color,
borderWidth: 1,
label: "開收價",
data: openEnd,
barPercentage: 10, // 調整長條圖的寬度
categoryPercentage: -0.1, // 調整長條圖組內間距
},
{
type: "bar",
backgroundColor: "black",
borderColor: "black",
label: "高低價",
data: highLow,
barPercentage: 0.5,
categoryPercentage: 0.1,
},
],
},
options: {
scales: {
y: {
min: Math.round(min) - (Math.round(max) - Math.round(min)), // y 軸的最小值
max: Math.round(max) + (Math.round(max) - Math.round(min)), // y 軸的最大值
},
},
},
});

個股相關新聞:

關於個股相關新聞則是用爬蟲的方式來實現,套件是選擇 cheerio ,非常貼心的有中文說明文檔,就直接用我的程式碼來說明,但因為 cheerio 只能爬靜態網站並不具備瀏覽器的功能,無法自動執行點擊事件或導航到下一頁,所以我們要分開寫爬單一頁面的 crawler function 與執行下一頁的getStockNews function。

cheerio 說明文檔中文版:
Chinese README · cheeriojs/cheerio Wiki (github.com)

新聞網站:
台積電 | 搜尋結果 | 經濟日報 (udn.com)

const request = require("request");
const cheerio = require("cheerio");

// 爬單一頁面新聞
const crawler = async (stockName, url) => {
return new Promise((resolve, reject) => {
request(
// 發送 GET 請求到指定的 URL
{
url: url,
method: "GET",
},
// 錯誤處理
(error, res, body) => {
if (error || !body) {
reject(error);
return;
}
// 載入body
const $ = cheerio.load(body);
// 選擇新聞所在的DOM的節點
const newsList = $(".story-headline-wrapper");
const data = [];
// 找新聞 title/date/link
for (let i = 0; i < newsList.length; i++) {
// eq(i)由cheerio提供可以把它理解為陣列的[i]
const title = newsList.eq(i).find(".story__headline").text().trim();
const date = newsList.eq(i).find(".story__content time").text();
const link = newsList.eq(i).find(".story__content a").attr("href");
// 逐一確認title是否符合股票名稱
for (let j = 0; j < title.length - stockName.length; j++) {
const subString = title.slice(j, j + stockName.length);
if (subString === stockName) {
data.push({ title, date, link });
}
}
}
resolve(data);
}
);
});
};
// 爬特定股票新聞
const getStockNews = async (stockName, page = 1) => {
// 將股票中文名稱轉換成 UTF-8 編碼
const keyword = encodeURIComponent(stockName);
let data = [];
// 找10個相關新聞
let target = 10;
while (data.length < target) {
let url = `https://money.udn.com/search/result/1001/${keyword}/${page}`;
let pageNews = await crawler(stockName, url);
data = data.concat(pageNews);
// 若相關新聞太少,找5頁就好
if (page >= 5 && data.length < target) {
return data;
}
if (data.length > target) {
data.splice(target - data.length);
}
page++;
}
return data;
};

加入自選股功能:

使用者可以將股票加入自選股清單中,網站會自動與 0050 比較近期一個月的表現

這邊的折線圖就沒什麼特別的,基本上就是把 type 更改為 line、把主要比較對象 0050 的折線加粗(borderWidth)。

// 先獲取使用者的自選股清單 => 個別查詢近期股價整理成 datasets
// 代碼實踐部分省略...

// chartjs畫圖
// 一樣先選擇圖表要放置的位置
const ctx = document.getElementById("container");
const myChart = new Chart(ctx, {
type: "line", // 圖表類型
data: {
labels: date, // X軸座標
datasets: datasets, // Y軸資料
},
options: {
scales: {
// X軸座標單位設定
x: {
title: {
display: true,
text: "日期",
font: {
size: 14,
weight: "bold",
},
},
},
// Y軸座標單位設定
y: {
title: {
display: true,
text: "%",
font: {
size: 14,
weight: "bold",
},
},
},
},
},
});

心得:

其實在動手做之前並沒有太多想法,只大概有畫K線圖與自選股表現比較而已(畢竟若表現不如 0050 那定投就好啦),做了之後想法才開始冒出來(爬相關新聞、大盤表現等等)不過這才第一版,下次有機會想把技術指標加入。

--

--