股市數據爬取與分析

股市數據爬取與分析

大綱

證券櫃檯買賣中心

證券櫃檯買賣中心是台灣上櫃股票的買賣中心,本文我們將講解獲取特定股票的是 CSV 檔案方式,然後做基礎股票分析 。

獲得特定上櫃股票的 CSV 檔案

請進入 證券櫃檯買賣中心網頁

點選上櫃 =>盤後資訊 => 個股日成交資訊,可以看到下列畫面 :

讀者可以參考上述圈選欄位,自行輸入股票代碼和資料年月,就可以看到特定股票在特定年月份的成交盤後資訊。下列是筆者填選 110/09 月份,股票代碼 6488 環球晶的盤後資訊

上述可以看到另存 CSV 按鈕,點選就可以下載,下列是我們以 Microsoft Excel 開啟此檔案的畫面 。

同時我們也使用相同名稱 ST43_6488_202109.csv 儲存此 CSV 檔案。

一個月的收盤價分析

我們有了上述 CSV 檔案,就可以使用我們了解的繪圖知識,製作股價走勢圖,當然在製作前我們必須了解此 CSV 檔案,才可以讀取我們想要的內容。首先這個檔案的前 5 行是股票基本訊息,我們可以忽略,此外最後一行是計算本月成交的日期數,也稱成交筆數,我們也須忽略,可以參考以下範例。

範例 pythonStock-01.py : 設計上櫃股票,股票代號是 6488 的 2021 年 9 月,每天最高價、最低價、收盤價的股票走勢圖。這個程式設計中,我們先將所讀取的 csv 檔案轉成串列 list,然後使用串列切片觀念,刪除前5行和最後一行。

# pythonStock-01.py
import csv
import matplotlib.pyplot as plt
from datetime import datetime

fn = 'ST43_6488_202109.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    listCsv = list(csvReader)                   # 轉成串列
    csvData = listCsv[5:-1]                     # 切片刪除非成交資訊
    dates, highs, lows, prices = [], [], [], [] # 設定空串列
    for row in csvData:
        try:
            datestr = row[0].replace('110','2021')
            currentDate = datetime.strptime(datestr, "%Y/%m/%d")
            high = float(row[4])                # 設定最高價
            low = float(row[5])                 # 設定最低價
            price = float(row[6])               # 設定收盤價
        except Exception:
            print('有缺值')
        else:
            highs.append(high)                  # 儲存最高價
            lows.append(low)                    # 儲存最低價
            prices.append(price)                # 儲存收盤價
            dates.append(currentDate)           # 儲存日期
       
fig = plt.figure(dpi=80, figsize=(12, 8))       # 設定繪圖區大小
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']        # 使用黑體
plt.plot(dates, highs, '-*', label='High')      # 繪製最高價
plt.plot(dates, lows, '-o', label='Low')        # 繪製最低價
plt.plot(dates, prices, '-^',   label='Price')  # 繪製收盤價
plt.legend(loc='best')
fig.autofmt_xdate()                         # 日期旋轉
plt.title("6488 環球晶 , 2021 年 9 月", fontsize=24)
plt.xlabel("", fontsize=14)
plt.ylabel("股 價", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

執行結果

上述中間的線條就是當日的收盤價數據線。

台灣證券交易所

台灣證券交易所是台灣上市股票的買賣中心,這裡我們將講解此網站相關個股市資訊,請點選 
台灣證券交易所

獲得特定上市股票的盤後資訊

請點選交易資訊 => 盤後資訊 => 個股年成交資訊,然後輸入1101 選擇台泥,再按 "查詢按鈕",可以得到下列畫面 : 


台灣證券交易所是從 80年開始做統計,基本上可以看到從 80年到去年的年度成交資訊,從上圖可以看到上述資料可以直接下載 csv 檔案,如果你是從事股票分析相關工作,這將是你取得寶貴資訊的來源。此例,我們直接下載,然後儲存到資料夾,如下所示 

台泥年度收盤價分析

我們有了上述 CSV 檔案,就可以使用我們了解的繪圖知識,製作股票走勢圖,然後在製作前,我們必須了解此檔案,才可以讀取我們想要的內容。首先,這個檔案的前 2 行是股票基本資訊,我們可以忽略,此外最後 5 行是計算近年最高價、最低價以及備註資訊,我們也必須忽略。

上述可以使用切片 [2:-5] 排除,有了上述觀念,我們就可以使用此 CSV 檔案設計程式了。

範例 pythonStock-02.py : 設計上市股票台泥股票代號 1101 的 1991 年至 2020 年,每年最高價、最低價、收盤平均價的股票走勢圖 。

# pythonStock-02.py
import csv
import matplotlib.pyplot as plt
from datetime import datetime

fn = 'FMNPTK_1101.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    listCsv = list(csvReader)                   # 轉成串列
    csvData = listCsv[2:-5]                     # 切片刪除非成交資訊
    years, highs, lows, prices = [], [], [], [] # 設定空串列
    for row in csvData:
        try:
            year = int(row[0]) + 1911
            high = float(row[4])                # 設定最高價
            low = float(row[6])                 # 設定最低價
            price = float(row[8])               # 設定收盤平均價
        except Exception:
            print('有缺值')
        else:
            highs.append(high)                  # 儲存最高價
            lows.append(low)                    # 儲存最低價
            prices.append(price)                # 儲存收盤平均價
            years.append(year)                  # 儲存日期
       
fig = plt.figure(dpi=80, figsize=(12, 8))       # 設定繪圖區大小
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']        # 使用黑體
plt.plot(years, highs, '-*', label='最高價')      # 繪製最高價
plt.plot(years, lows, '-o', label='最低價')        # 繪製最低價
plt.plot(years, prices, '-^',   label='收盤平均價')  # 繪製收盤平均價
plt.legend(loc='best')
fig.autofmt_xdate()                         # 日期旋轉
plt.title("1101 台泥,1991 - 2020 年度收盤價", fontsize=24)
plt.xlabel("", fontsize=14)
plt.ylabel("價格", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

執行結果

獲得每天股票每5秒的成交資訊

台灣證券交易所首頁,請點選交易資訊 => 盤後資訊 => 每5秒委託成交統計,可以看到今天股票每 5 秒的統計資訊。

同樣我們可以使用下載 csv 檔案方式取得上述資料, 由於是每 5 秒提供一筆資料,所以有幾千行,上述 csv 檔案的名稱是 MI_5MINS_20211018.csv,如果我們只想要每30分鐘取得一次累積資料,可以參考下列程式 :

範例 pythonStock-03.py :  讀取MI_5MINS.csv 檔案,每30分鐘將一筆數據的時間和累積成交述欄位寫入 MI_30MINS.csv 內。

# pythonStock-03.py
import csv

fn = 'MI_5MINS.csv'                             # 台灣證劵交易所資料
out = 'MI_30MINS.csv'                           # 每30分鐘資料
with open(out, 'w', newline='') as csvOut:
    csvWriter = csv.writer(csvOut)
    csvWriter.writerow(["時間", "累積成交數"])
    with open(fn) as csvFile:
        csvReader = csv.reader(csvFile)
        listCsv = list(csvReader)               # 轉成串列
        csvData = listCsv[2:-8]                 # 切片刪除非成交資訊
        for row in csvData:
            xmin = row[0][3:5]                  # 分
            xsec = row[0][6:]                   # 秒
            if xmin == '00' or xmin == '30':    # 每30分鐘
                if xsec == '00':                # True時寫入時間和累積成交數
                    csvWriter.writerow([row[0], row[6]])
                    print(row[0], row[6])

執行結果

範例 pythonStock-04.py :  讀取MI_30MINS.csv 檔案資料繪製折線圖。

# pythonStock-04.py
import csv
import matplotlib.pyplot as plt
from datetime import datetime

fn = 'MI_30MINS.csv'
with open(fn) as csvFile:
    csvReader = csv.reader(csvFile)
    listCsv = list(csvReader)                   # 轉成串列
    csvData = listCsv[1:]                       # 切片刪除非成交資訊
    times, items = [], []                       # 設定空串列
    for row in csvData:
        try:
            time = row[0]                       # 時間
            item = row[1]                       # 累積成交數
        except Exception:
            print('有缺值')
        else:
            times.append(time)                  # 儲存時間
            items.append(item)                  # 儲存累積成交數
       
fig = plt.figure(dpi=80, figsize=(12, 8))       # 設定繪圖區大小
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']        # 使用黑體
plt.plot(times, items, '-*')                    # 繪製累積成交數
fig.autofmt_xdate()                             # 時間旋轉
plt.title("30分鐘累積交易量", fontsize=24)
plt.xlabel("", fontsize=14)
plt.ylabel("累積交易量", fontsize=14)
plt.tick_params(axis='both', labelsize=12, color='red')
plt.show()

執行結果

Google 全球股市資訊

Google 網站也有提供全球股市資訊,我們可以使用它查詢全球主要股市的資訊,若是以 台泥 為例,它的股市代號是 1101,可以使用下列基本網址查詢台泥股票

https://www.google.com/search?q=TPE:1101

上述 TPE 是台北股市,1101 則是台灣水泥的股票代號,如果想查詢台積電,台積電在台北股市代號是 2330,所以下列網址可以連結台積電股市資訊

https://www.google.com/search?q=TPE:2330

下列是美國股市資料範例

  • NASDAQ:GOOG  (美國那斯達克 Alphabet 股票)
  • NASDAQ:AAPL  (美國那斯達克 Apple 股票)
  • NASDAQ:MSFT (美國那斯達克 Microsoft 股票)
  • NYSE:DOW J  (美國紐約證券交易所 道瓊工業指數)
  • NYSE:BABA  (美國紐約證券交易所 阿里巴巴)
下列是台灣水泥公司的股市執行結果畫面。在這裡我們將爬取上述上方圈起來的公司名稱和下方框起來的股價相關資訊 ,我們使用 Chrome 分析台灣水泥公司名稱時可以看到公司名稱資料是放在 <g-card-section> 區塊內:

其實有許多層次,如果使用 Chrome 分析網頁,下方的公司股價相關資訊可以看到下列畫面 


範例 pythonStock-05.py :  使用爬蟲爬取 Google 財經網站,列出台泥當日最新價格、前日收盤價、單日股價範圍。

# pythonStock-05.py
import requests, bs4

url = 'https://www.google.com/finance/quote/1101:TPE'
headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64)\
            AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101\
            Safari/537.36', }
newshtml = requests.get(url, headers=headers)           # 台灣水泥
objSoup = bs4.BeautifulSoup(newshtml.text, 'lxml')      # 取得HTML
companyInfo = objSoup.find('main')                 # 主要資訊區塊
companyName = companyInfo.find_all('div',attrs={'role':'heading'})    # 取得公司名稱
print('公司名稱 : ',companyName[1].text)    
price = companyInfo.find('div','YMlKec fxKbKc')   # 取得最新報價
print('最新報價 : ', price.text)
detailsTable = companyInfo.find_all('div','P6K39c')    # 取得公司詳細資訊表
print('前日收盤價', detailsTable[0].text)      # 前日收盤價
print('單日股價範圍', detailsTable[1].text)   # 單日股價範圍

執行結果

公司名稱 :  Taiwan Cement Corp
最新報價 :  $49.45
前日收盤價 $49.80
單日股價範圍 $49.85 - $50.10

Yahoo 股市資訊

進入 Yahoo 股市資訊網頁 => 輸入股票代號或名稱,這裡我們輸入 : 2330 => 畫面出現 2330 台積電的股票資訊,如下 : 

我們使用 Chrome 瀏覽器的分析工具來解析網頁 => 按 F12 鍵 => 1. 右邊工具區塊的左上角選擇 "點選元素圖示" => 2. 再將滑鼠移到左邊網頁區塊,會發現不斷的有反白區塊,最後我們找到主要的資訊區塊 <section id='qsp-overview-realtime-info'>,如下圖 :

有了以上的資訊區塊,我們就可以寫爬蟲程式了。

範例 pythonStock-06.py :  使用爬蟲爬取 Yahoo 股市網站,列出 2330 台積電 股票相關資訊。

# pythonStock-06.py
import requests, bs4

url = 'https://tw.stock.yahoo.com/quote/2330'   # 2330 台積電
headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64)\
            AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101\
            Safari/537.36', }
newshtml = requests.get(url, headers=headers)           
objSoup = bs4.BeautifulSoup(newshtml.text, 'lxml')      # 取得HTML
companyInfo = objSoup.find('section', id='qsp-overview-realtime-info')   # 主要資訊區塊
companyName = companyInfo.find('h2')    # 取得公司名稱
print('公司名稱 : ', companyName.text)
time = companyInfo.find('time').find_all('span')[2]
print('資料時間:', time.text)
priceDetailItems = companyInfo.find_all('li', 'price-detail-item')
for item in priceDetailItems:
  print(item.text)

執行結果

公司名稱 :  台積電即時行情
資料時間: 2021/10/19 11:35
成交599
開盤598
最高600
最低593
均價598
成交值(億)62.41
昨收590
漲跌幅1.53%
漲跌9
總量10,440
昨量19,120
振幅1.19%

台灣股市資料讀取與圖表製作

前面我們介紹了自行到台灣證券交易所與櫃檯買賣中心爬取股市資料與簡單分析的方法,其實目前已經有前背設計了股市好用的模組工具提供我們使用,這裡我們將介紹 twstock 這個模組,讀取台灣股票資訊,同時利用本文知識建立折線圖表。

使用前需安裝模組

pip install twstock

導入

import twstock

讀者可以參考下列網址了解更完整的資訊

https://twstock.readthedocs.io/zh_TW/latest/

stock建構元

可以使用 Stock() 建構元傳入股票代號,然後可以傳回此股票代號的 Stock 物件。台灣著名的股票台積電的股票代號是 2330 ,如果輸入 2330 ,即可以獲得台積電的股票的物件。

Stock物件屬性

有了前面的 Stock 物件後,可以參考下列表格獲得物件屬性

Stock物件屬性 說明
sid 股票代號字串
open 近31天的開盤價串列
high 近31天的最高價串列
low 近31天的最低價串列
close 或 price 近31天的收盤價串列
capacity 近31天的成交量串列
transaction 近31天的成交筆數串列
turnover 近31天的成交金額串列
change 近31天的漲跌幅串列
date 近31天的交易日期物件串列
data 近31天的Stock物件全部資料內容串列
raw_data 近31天的原始資料串列

範例 pythonStock-07.py :  獲得台積電股票代號和近31天的收盤價。

# pythonStock-07.py
import twstock
stock2330 = twstock.Stock("2330")

print("股票代號   : ", stock2330.sid)
print("股票收盤價 : ", stock2330.price)

執行結果

股票代號   :  2330
股票收盤價 :  [613.0, 607.0, 620.0, 631.0, 623.0, 619.0, 619.0, 622.0, 615.0, 613.0, 607.0, 600.0, 600.0, 586.0, 588.0, 598.0, 602.0, 594.0, 580.0, 580.0, 574.0, 572.0, 572.0, 571.0, 580.0, 575.0, 575.0, 571.0, 573.0, 600.0, 590.0]

在所傳回的31天收盤價串列中,[0] 是最舊的收盤價,[31] 是前一個交易日的收盤價。

實例 1 : 傳回台積電31天前的收盤價與前一個交易日的收盤價。

實例 2 : 了解台積電 data 屬性的全部內容,可以使用 data 屬性,此例我們只是列出部分內容。

在 Stock 屬性中,除了股票代號 sid 是傳回字串外,其他皆是傳回串列,此時我們可以使用切片方式處理

實例 3 下列是傳回台積電近 5 天的股票收盤價

範例 pythonStock-08.py : 列出近31天台積電收盤價的折線圖。

# pythonStock-08.py
import matplotlib.pyplot as plt
import twstock

stock2330 = twstock.Stock("2330")
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']        # 使用黑體
plt.title("2330 台積電", fontsize=24)
plt.plot(stock2330.price)
plt.show()

執行結果

Stock 物件方法

有了之前說明的 Stock 物件後,可以參考下表獲得物件方法

Stock物件方法 說明
fetch_31 近31天的交易資訊(Data物件) 串列
fetch(year, month) 指定年月的交易資訊(Data物件) 串列
fetch_from(year, month) 指定年月至今的交易資訊(Data物件) 串列
moving_average(data,days) 串列數據 data 的 days 日平均值串列
continuous(data) 串列 data 持續上漲天數

實例 1 傳回2021年9月的台積電股市交易資訊下列只列出部分結果

實例 2 接續以上實例,傳回2020年9月台積電收盤價格資訊

方法 moving_average(data,days) 是傳回均線串列,這個方法需要兩個參數, days 天數是代表幾天均線,例如,若是第二個參數是 5,則代表5天均線值,所謂的5天均線值,指的是第0到4筆資料平均值當作的第 0 筆,第 1 - 5 筆資料平均值當作第 1 筆.....等,所以均線資料串列元素會比較少。

實例 2 :  接續以上實例,傳回2021年9月台積電收盤價格資料的 5 日均線資料串列。

實例 3 接續以上實例,傳回2021年9月台積電收盤價格資料的5天均線資料串列的連續上漲天數,留意每天做比較如果上漲會加1,下跌會減1。

範例 pythonStock-09.py : 以折線圖列出台積電2021年1月以來的收盤價格資料。

# pythonStock-09.py
import matplotlib.pyplot as plt
import twstock

plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']        # 使用黑體
stock2330 = twstock.Stock("2330")
stock2330.fetch_from(2021,1)
plt.title("2330 台積電", fontsize=24)
plt.xlabel("2021年1月以來的交易天數", fontsize=14)
plt.ylabel("價格", fontsize=14)
plt.plot(stock2330.price)
plt.show()

執行結果

取得單一股票之即時資料 realtime.get()

在使用 twstock 模組時,可以使用 realtime.get() 取得特定股票的即時資訊,這些資訊包含股票代號 code、名稱 name、全名 fullname、收盤時間 time ..等等,同時有包含目前五檔買進和賣出的金額與數量。

實例 1 列出台積電的即時資料。

實例 2延續前一實例,列出目前五檔買進金額與數量。

實例 3延續前一實例,列出目前五檔賣出金額與數量

範例 pythonStock-10.py : 參考上述實例,將最佳五檔買進賣出使用 pandas 處理,以表單方式顯示。

# pythonStock-10.py
import pandas as pd
import twstock

stock2330 = twstock.realtime.get('2330')
buyPrice = stock2330['realtime']['best_bid_price']
buyNum = stock2330['realtime']['best_bid_volume']

sellPrice = stock2330['realtime']['best_ask_price']
sellNum = stock2330['realtime']['best_ask_volume']

dict2330 = {'BVolumn':buyNum,
            'Buy':buyPrice,
            'Sell':sellPrice,
            'SVolumn':sellNum}

df2330 = pd.DataFrame(dict2330, index=range(1,6))
print("台積電最佳五檔價量表")
print(df2330)

執行結果

台積電最佳五檔價量表
   BVolumn   Buy      Sell    SVolumn
1      72  599.0000  600.0000    1947
2      76  598.0000  601.0000     962
3     202  597.0000  602.0000    1048
4     247  596.0000  603.0000     943
5     308  595.0000  604.0000     822


參考資料

特色、摘要,Feature、Summary:

關鍵字、標籤,Keyword、Tag:

  • Web-Crawler,Data-Mining,Data-Science,Python,Fintech-AI,

留言

這個網誌中的熱門文章

Ubuntu 常用指令、分類與簡介

iptables的觀念與使用

網路設定必要參數IP、netmask(遮罩)、Gateway(閘道)、DNS

了解、分析登錄檔 - log

Python 與SQLite 資料庫

Blogger文章排版範本

Pandas 模組

如何撰寫Shell Script

查詢指令或設定 -Linux 線上手冊 - man

下載網頁使用 requests 模組