close

【Plotly】Python台股漲跌幅板塊製作:一秒看出台股類股漲跌 你知道最近漲什麼類股嗎?

image

一、前言

想一眼就看出哪個類股強嗎?今天漲哪個類股你知道嗎?

或是順便學點plotly提供的python api也可以看過來。

或單純覺得板塊圖很美想畫畫看也可以看過來,手把手帶到好。

 

進入基本教學前,不要忘了訂閱按讚分享唷!

部落格教學網站:
https://pixnashpython.pixnet.net/blog
想要即時訂閱最新文章:
https://forms.gle/MdXmiF2HgHhNChL46
訂閱Telegram來接收最新資訊:
https://t.me/joinchat/VUUuDt67Uq5l6CIQ

 

 

二、下載期交所證券分類編碼


先到證交所的證券編碼分類下弄一張分類表出來,總要知道這檔股票是屬於哪個產業吧,

不會弄得就照下面步驟,除非你要自己900多檔自己手動key產業,那我也是笑笑的~

會弄的或自己已經有分類表的就可以直接跳過,最下面有要整理成的格式可以參考。

 

(1) 到證交所的編碼公告抄一張分類表

可以直接到證交所<本國上市證券國際證券辨識號碼一覽表>點進去全選複製到excel上面。

證交所證券編碼:https://www.twse.com.tw/zh/page/products/stock-code2.html

image

image

 

(2) 快速整理成以下格式

複製到excel之後整理成下面的格式即可,什麼都可以不要就股票代號、名稱、產業分類要有,接下來我們就可以進行下一個步驟了。

image

 

 

三、取得期交所資料


這個應該教好幾遍了,用requests把證交所資料爬下來並進行點單處理,

不懂的可以看【Python量化資料】Python爬取台灣證交所資料:取得台股每日收盤行情

(https://pixnashpython.pixnet.net/blog/post/47994067)

這邊把它包成類的形式並直接在裡面把資料格式處理好方便我們之後呼叫,

資料處理部分看不懂的可以到我pandas專區裡面都有答案。

(https://pixnashpython.pixnet.net/blog/category/461784)

class API_TWSE(object):
    def __init__(self):
        pass
    
    def get_TWSE_data_oneday(self, date):
        try:
            # 爬蟲
            Agent = random.choice([1,2,3,4,5,6,7,8,9])
            headers = {'User-Agent': 'Mozilla/' + str(Agent) + '.0'}
            date_f = date.strftime('%Y%m%d')
            
            url = 'https://www.twse.com.tw/exchangeReport/MI_INDEX?response=json&date=' + date_f + '&type=ALLBUT0999&_=1620615911060'
            re = requests.get(url, headers=headers)
            data = json.loads(re.text)
            # 資料處理
            df_STOCK = pandas.DataFrame(data['data9'])
            df_STOCK[9] = [x.split('>')[1][0].replace('X', '') for x in df_STOCK[9]]
            df_STOCK[9] = df_STOCK[9] + df_STOCK[10]
            df_STOCK.insert(0, 'Date', date) # 新增日期 # pandas.to_datetime(data['date'])會錯
            df_STOCK.insert(1, 'Exchange', 'TWSE') # 交易所
            df_STOCK.insert(1, 'Symbol', 'TW' + df_STOCK[0]) # 交易所
            df_STOCK = df_STOCK.replace(',', '', regex=True) # 資料處理
            df_STOCK = df_STOCK.replace('--', 0, regex=True) # 資料處理
            df_STOCK = df_STOCK.replace('', 0, regex=True) # 資料處理
            df_STOCK.iloc[:,5:] = df_STOCK.iloc[:,5:].astype('float32')
            df_STOCK.index = df_STOCK['Symbol']
            
            return df_STOCK
        
        except Exception as e:
            return e.args[0]
                

 

 

四、將資料抽取並進行分類


把證交所爬下來的表用迴圈跑一次,並把有剛剛在分類出現過的股票找到產業別塞回去,

如此程式就可以判斷這檔股票是屬於哪個產業板塊裡面的了。

if __name__ == '__main__':
    API_TWSE = API_TWSE()
    # 取得資料
    today = datetime.datetime(2021,9,29)
    last = today - datetime.timedelta(1)
    
    dftoday = API_TWSE.get_TWSE_data_oneday(today); print(dftoday) # 取得當天股票資料
    
    dflast = API_TWSE.get_TWSE_data_oneday(last); print(dflast) # 取得要比較股票資料
    
    dftoday['Ret'] = ((dftoday[7] - dflast[7]) / dflast[7]).round(4) # 計算報酬
    
    df = dftoday.copy()
    
    # 取得分類
    path = r'classify.csv'
    classify = pandas.read_csv(path)
    
    df['Classify'] = 'other'
    
    
    # 資料處理
    for t in range(0, df.index.size):
        c = classify[classify['Symbol'] == df['Symbol'][t]]
        try:
            df['Classify'][t] = c['Classify'].iloc[0]
        except:
            df['Classify'][t] = 'Other'

API_TWSE = API_TWSE() 用剛剛寫的類實體化成物件

today = datetime.datetime(2021,9,29) 要顯示哪天收盤價

last = today - datetime.timedelta(1) 要比較前n天的收盤價,計算漲跌幅用。

dftoday = API_TWSE.get_TWSE_data_oneday(today); print(dftoday)  取得當天股票資料

dflast = API_TWSE.get_TWSE_data_oneday(last); print(dflast) 取得要比較股票資料

dftoday['Ret'] = ((dftoday[7] - dflast[7]) / dflast[7]).round(4) 計算報酬 第7欄為收盤價

df['Classify'] = 'other' 一開始都把產業設為其他

如果再for迴圈有找到對應產業在塞回去即可

 

 

五、使用Plotly提供給Python的套件包


(1) 在python安裝plotly

如果沒辦法安裝可以試試看pip install plotly-python看看

pip install plotly

 

(2) import plotly

兩個都匯入才有辦法在瀏覽器顯示,因為最後需要用pltoff.plot(fig)呼叫

import plotly.express as px 
import plotly.offline as pltoff

 

(3) 使用treemap方法

   
    # 格式化所需文字
    df['Retf'] = (df['Ret'].round(4) * 100).astype('float16').astype(str)
    df['Closef'] = (df[8].round(2)).astype('float16').astype(str)
    df['Name'] = df[1]
    df['Volume'] = df[4]
    
    # 資料過濾
    df_plot = df[df['Volume']!=0]
    
    # 繪圖
    fig = px.treemap(df_plot, path=[px.Constant("TWSE"), 'Classify', 'Symbol'], values='Volume',
                     custom_data=['Name', 'Retf','Closef'],
                     color='Ret', 
                     color_continuous_scale='Tealrose',
                     color_continuous_midpoint=0#numpy.average(df_plot['Ret'], weights=df_plot['Volume'])
                     )
    
    fig.update_traces(textposition='middle center', 
                      textfont_size=24,
                      texttemplate= "%{label}<br>%{customdata[0]}<br>%{customdata[1]}%<br>Close: %{customdata[2]}"
                      )
    
    pltoff.plot(fig)

path=[px.Constant("TWSE"), 'Classify', 'Symbol'] 分別為板塊第一層 第二層 第三層

values='Volume' 板塊大小用交易量決定

color='Ret' 板塊顏色用報酬率決定

custom_data=['Name', 'Retf','Closef'] 我們客製化的文字放我們剛剛格式化好的文字以便顯示

color_continuous_scale='Tealrose' 配色

color_continuous_midpoint=0 顏色的中間值為0

用fig.update_traces設定板塊顯示內容及排版

textposition='middle center' 板塊內文字置中

textfont_size=24 大小

最後是下面這一串,可以很簡單的當成要顯示的內容%{customdata[0]}為剛剛設置custom_data=['Name', 'Retf','Closef']的第一個也就是Name,依此類推。

texttemplate= "%{label}<br>%{customdata[0]}<br>%{customdata[1]}%<br>Close: %{customdata[2]}"

image

 

 

完整程式碼

import pandas, numpy
import datetime
import requests
import plotly.express as px
import plotly.offline as pltoff
import json
import random

# 計時器
def dtimer(func):
    
    def inner(*arg):
        start = datetime.datetime.now()
        ret = func(*arg)
        end = datetime.datetime.now()
        print(func.__name__, end-start)
        return ret
    
    return inner

# 期交所api
class API_TWSE(object):
    def __init__(self):
        pass
    
    @dtimer # 使用計時器
    def get_TWSE_data_oneday(self, date):
        try:
            # 爬蟲
            Agent = random.choice([1,2,3,4,5,6,7,8,9])
            headers = {'User-Agent': 'Mozilla/' + str(Agent) + '.0'}
            date_f = date.strftime('%Y%m%d')
            
            url = 'https://www.twse.com.tw/exchangeReport/MI_INDEX?response=json&date=' + date_f + '&type=ALLBUT0999&_=1620615911060'
            re = requests.get(url, headers=headers)
            data = json.loads(re.text)
            # 資料處理
            df_STOCK = pandas.DataFrame(data['data9'])
            df_STOCK[9] = [x.split('>')[1][0].replace('X', '') for x in df_STOCK[9]]
            df_STOCK[9] = df_STOCK[9] + df_STOCK[10]
            df_STOCK.insert(0, 'Date', date) # 新增日期 # pandas.to_datetime(data['date'])會錯
            df_STOCK.insert(1, 'Exchange', 'TWSE') # 交易所
            df_STOCK.insert(1, 'Symbol', 'TW' + df_STOCK[0]) # 交易所
            df_STOCK = df_STOCK.replace(',', '', regex=True) # 資料處理
            df_STOCK = df_STOCK.replace('--', 0, regex=True) # 資料處理
            df_STOCK = df_STOCK.replace('', 0, regex=True) # 資料處理
            df_STOCK.iloc[:,5:] = df_STOCK.iloc[:,5:].astype('float32')
            df_STOCK.index = df_STOCK['Symbol']
            
            return df_STOCK
        
        except Exception as e:
            return e.args[0]
                



if __name__ == '__main__':
    API_TWSE = API_TWSE()
    # 取得資料
    today = datetime.datetime(2021,9,29)
    last = today - datetime.timedelta(1)
    
    dftoday = API_TWSE.get_TWSE_data_oneday(today); print(dftoday) # 取得當天股票資料
    
    dflast = API_TWSE.get_TWSE_data_oneday(last); print(dflast) # 取得要比較股票資料
    
    dftoday['Ret'] = ((dftoday[7] - dflast[7]) / dflast[7]).round(4) # 計算報酬
    
    df = dftoday.copy()
    
    # 取得分類
    path = r'classify.csv'
    classify = pandas.read_csv(path)
    
    df['Classify'] = 'other'
    
    
    # 資料處理
    for t in range(0, df.index.size):
        c = classify[classify['Symbol'] == df['Symbol'][t]]
        try:
            df['Classify'][t] = c['Classify'].iloc[0]
        except:
            df['Classify'][t] = 'Other'
        
    
    # 格式化所需文字
    df['Retf'] = (df['Ret'].round(4) * 100).astype('float16').astype(str)
    df['Closef'] = (df[8].round(2)).astype('float16').astype(str)
    df['Name'] = df[1]
    df['Volume'] = df[4]
    
    # 資料過濾
    df_plot = df[df['Volume']!=0]
    
    # 繪圖
    fig = px.treemap(df_plot, path=[px.Constant("TWSE"), 'Classify', 'Symbol'], values='Volume',
                     custom_data=['Name', 'Retf','Closef'],
                     color='Ret', 
                     color_continuous_scale='Tealrose',
                     color_continuous_midpoint=0#numpy.average(df_plot['Ret'], weights=df_plot['Volume'])
                     )
    
    fig.update_traces(textposition='middle center', 
                      textfont_size=24,
                      texttemplate= "%{label}<br>%{customdata[0]}<br>%{customdata[1]}%<br>Close: %{customdata[2]}"
                      )
    
    pltoff.plot(fig)

 

 

五、後記


下次還想看我去哪裡取得資料嗎?趕快留言給我!

 

部落格教學網站:
https://pixnashpython.pixnet.net/blog
想要即時訂閱最新文章:
https://forms.gle/MdXmiF2HgHhNChL46
訂閱Telegram來接收最新資訊:
https://t.me/joinchat/VUUuDt67Uq5l6CIQ

 

arrow
arrow

    恩哥Python 發表在 痞客邦 留言(0) 人氣()