2025年1月31日 星期五

2025年1月29日 星期三

Mapleboard MP510-50 測試 (二十一) : Hinet 浮動制固定 IP 異動

月初時收到 Hinet 通知, 我的光世代所申請的浮動制固定 IP 因機房更新作業已更換 IP, 但一月份我都在忙量化投資的東西, 沒時間配合處理, 所以這陣子連線到我申請的 tony1966.cc 域名都無法顯示網頁 : 




趁春節連假有整整一周待在鄉下, 今天大年初一早上要拜廟, 下午無事就來處理此問題. 依照信中指示須將 Mapleboard 重開機才能抓到新的固定 IP :




重開機後用 ifconfig 確認已抓到信中所述新的固定 IP :




但接下來還須更新 Namecheap 的網域名稱 DNS 對應表中的 IP 才能順利連線到我申請的域名, 參考之前的文章 : 


連線 Namecheap 官網按按左上角的 "SIGN IN" : 






登入成功後按 Dashboard 下的 Domain List : 





按域名列表最右邊的 Manage 鈕進入管理頁面 : 





按最右邊的 Advanced DNS : 





這是原先的域名設定連接到舊的固定 IP 122.117.150.208, 沒有編輯按鈕可更改舊 Record, 必須按底下的 Add new record 新增一筆紀錄 : 




Type 欄勾選 A record, Host 欄填入 @, Value 欄填入新的固定 IP, 按底下的打勾勾按鈕即完成新增設定 : 






大約等 10 分鐘後連線 tony1966.cc 即可看到網頁了 : 



2025年1月28日 星期二

2025 年第 4 周記事

本周末進入春節連假, 週五下班前把辦公桌擦洗一番後將筆電關機讓它也休個年假. 

這兩天超忙, 我週五晚上回鄉下, 週六早上去市集採買週日安金第 12 天要用的水果三份, 下午整理二樓祖堂與客廳茶几下雜物. 週日早上去墓園上香奉茶燒金, 下午整理客廳大門側的雜物, 意外地找到去年遺失的 "Python 錦囊妙計" 這本書, 原來是掉在雜物堆, 遍尋不著之下只好上 momo 買了一本新的還圖書館 :




另外還找到一包去年過年未放完的沖天炮 :




試放了幾支還能發射 :




週日晚上回高雄順路去高鐵接二哥. 周一早上清理後陽台, 下午清前陽台與安裝太陽能感應燈, 晚上 23:00 出發到楠梓接菁菁回家過年. 今日除夕早上清理車庫清出一大堆垃圾, 等垃圾車來後則忙貼紅紙與祭祖, 可說這兩天是馬不停蹄, 好累. 



2025年1月27日 星期一

露天購買 KYNYO RA-5515 收音機

十多年前買了好幾台口袋型收音機, 一台給母親在菜園工作時解悶, 一台給二姨媽, 一台自用, 目前只剩一台還可正常使用, 平時在鄉下裝修或給芭樂套袋時都會放在旁邊聽廣播, 但所用的 NOKIA 鋰電池 BL-5C 有點膨脹, 想說與其買電池不如買新的收音機算了, 上露天找到下面這款 KYNYO 的, 它採用兩顆 18650, 且同樣有頻道按鈕, 就買了兩台一台放鄉下一台放高雄. 

其實還有一個原因啦, 最近常常周五晚上開夜車回鄉下, 發現 94.3 高雄電台 21:00~22:00 時段是空中英語教室廣播, 勾起退伍後連續聽了 20 年空英的美好回憶, 因為這奠定我後來進修時改讀外文系所的基礎, 現在我想恢復這習慣, 每天晚上九點開啟收音機聽空英. 






全家取或付款 660 元. 

好站 : 好用的 Markdown 線上編輯工具 StackEdit

最近為了撰寫 GitHub 的 README.md 說明文件, 找到一個好用的 Markdown 工具 :  


介面非常簡單, 左邊是 Markdown 語法編輯器, 右邊就是轉譯為 HTML 後的網頁呈現效果. 以撰寫最近要發佈到 PyPi 的 K 線圖繪製模組 kbar 的說明文件為例, 效果如下 : 




參考 :


2025年1月23日 星期四

高科大還書一本 : 區塊鏈生存指南 : 帶你用Python寫出區塊鏈

因預約書到館, 滿借情況下只好拿下面這本最近沒時間看的好書去換 :





因目前是寒假, 圖書館只到下午五點, 下班再去的話會來不及只好趁午休去借還書, 然後就去鄧園吃他們的招牌特製雞腿飯. 

2025年1月22日 星期三

momo 購買數位電視天線+健腹輪

昨天在蝦皮買了一個新的數位電視機上盒, 需要一個室內天線, 上 momo 買了這個 : 





但不滿 400 元要付 75 元運費, 乾脆再買一個去年放進購物車的健腹輪 :





合計 967 元扣抵 momo 幣 400 元實付 567 元, 1/24 到貨. 

有一個登記抽飛利浦音響活動 : 




2025-01-25 補充 :

天線 1/23 就收到了, 但 1/24 與機上盒一起晚上帶回鄉下安裝, 發現天線棒照其說明順時針轉入天線座均無法鎖上, 仔細看原來是天線棒口徑太小根本鎖不進天線座的螺絲, 研判是出廠時工人放錯規格的天線棒, 已申請退貨 : 




喜歡 ROSÉ 與 APT

最近迷上韓星 ROSÉ (朴彩英) 與她的洗腦舞曲 APT : 




因為 APT 翻譯成中文是 "啊! 罷之!", 台灣人就是戒不掉諧音梗, 哈哈. 

2025年1月21日 星期二

Python 學習筆記 : 如何在 K 線圖上填色

在前一篇關於 ta 套件的測試中曾經以布林傑通道為例繪製其上限, 中線, 與下限, 可否在上下限之間填色以強調通道的收歛與發散情況呢? 可以的, 只要利用 plot() 函式的 fill_between 參數即可, 本系列文章索引參考 :


首先從 Yahoo Finance 下載 0050 近半年來的價量資料 : 

>>> import yfinance as yf 
>>> df=yf.download('0050.TW', start='2024-08-20', end='2025-01-20')   
[*********************100%%**********************]  1 of 1 completed

然後用 ta 套件計算布林傑通道指標, 在 ta 官網搜尋 'bollinger' 即可找到其指標類別 ta.volatility.BollingerBands :





可見 ta 的布林傑指標類別預設滑動窗口是 20, 上下限之標準差預設為 2, 呼叫其建構式 ta.volatility.BollingerBands() 並傳入必要參數收盤價的 Series 物件即可建立 BollingerBands 指標物件 : 

>>> import ta 
>>> BB=ta.volatility.BollingerBands(df['Close'])    
>>> type(BB)  
<class 'ta.volatility.BollingerBands'>   

呼叫 BollingerBands 指標物件的 bollinger_mavg(), bollinger_hband(), 與 bollinger_lband() 方法會分別傳回布林傑中線, 與上下限之 Series 物件 :

>>> bbm=BB.bollinger_mavg()    # 中線
>>> bbh=BB.bollinger_hband()    # 上限
>>> bbl=BB.bollinger_lband()      # 下限
>>> type(bbm)   
<class 'pandas.core.series.Series'>
>>> type(bbh)   
<class 'pandas.core.series.Series'>
>>> type(bbl)   
<class 'pandas.core.series.Series'>
>>> bbm   
Date
2024-08-20           NaN
2024-08-21           NaN
2024-08-22           NaN
2024-08-23           NaN
2024-08-26           NaN
                 ...    
2025-01-13    197.592500
2025-01-14    197.567500
2025-01-15    197.417500
2025-01-16    197.465000
2025-01-17    197.560001
Name: mavg, Length: 103, dtype: float64
>>> bbh    
Date
2024-08-20           NaN
2024-08-21           NaN
2024-08-22           NaN
2024-08-23           NaN
2024-08-26           NaN
                 ...    
2025-01-13    203.157323
2025-01-14    203.163324
2025-01-15    203.212691
2025-01-16    203.264575
2025-01-17    203.216108
Name: hband, Length: 103, dtype: float64
>>> bbl    
Date
2024-08-20           NaN
2024-08-21           NaN
2024-08-22           NaN
2024-08-23           NaN
2024-08-26           NaN
                 ...    
2025-01-13    192.027678
2025-01-14    191.971676
2025-01-15    191.622309
2025-01-16    191.665426
2025-01-17    191.903893
Name: lband, Length: 103, dtype: float64

這樣就可以用 kbar.py 來繪製 K 線圖並疊上布林傑通道的中線, 上限, 與下限了 :

# kbar.py
import mplfinance as mpf

class KBar():
    def __init__(self, df):
        self.df=df
        self.addplots=[]
    def addplot(self, data, **kwargs):
        plot=mpf.make_addplot(data, **kwargs)
        self.addplots.append(plot)
    def plot(self, embedding=False, **kwargs):
        color=mpf.make_marketcolors(up='red', down='green', inherit=True)   
        font={'font.family': 'Microsoft JhengHei'}   
        style=mpf.make_mpf_style(base_mpf_style='default',
                                 marketcolors=color,
                                 rc=font)
        kwargs['type']='candle'
        kwargs['style']=style
        kwargs['addplot']=self.addplots
        if 'returnfig' in kwargs and kwargs['returnfig'] is True:
            fig, axes=mpf.plot(self.df, **kwargs)
            return fig, axes
        else:
            mpf.plot(self.df, **kwargs)

匯入 kbar 後呼叫 KBar 類別的建構函式並傳入價量 df 建立 KBar 物件 :

>>> import kbar   
>>> kb=kbar.KBar(df)    
>>> kb.addplot(bbh, color='red', width=1)       # 上限疊圖
>>> kb.addplot(bbm, color='blue', width=1)     # 中線疊圖 
>>> kb.addplot(bbl, color='green', width=1)     # 下限疊圖
>>> kb.plot(volume=True)      

結果如下 : 




接下來便是要在布林傑通道的上下限曲線之間填色, mplfinance 套件的 plot() 函式有一個 fill_between 參數可以用來在指定的 Y 軸區間填色, 用法參考 mplfinance 教學文件 :


fill_between 參數值為一個字典 (單區間填色) 或字典串列 (多區間填色), 字典中可用的鍵摘要說明如下表 : 


key (鍵) 名稱 說明
y1 第一條資料線的 Y 軸數值, 可以是與主圖索引等長對齊的 list 或一維 ndarray
y2 第二條資料線的 Y 軸數值, 可以是與主圖索引等長對齊的 list 或一維 ndarray
where 決定在哪些 X 軸區域填充顏色的布林值 Series 或 ndarray, 預設填充整個區域
color 指定要填充的顏色, 格式例如 'cyan' 或 '#00FFFF'
alpha 指定填充顏色的不透明度 (0~1), 預設為 0.5
interpolate 是否在資料之間內插以使邊界平滑 : True 或 False (預設)


注意, mplfinance 要求 fill_between 參數字典的 y1 與 y2 鍵只能是與 K 線圖資料等長對齊的 list 或一維 Numpy 陣列, 不可以傳入 Padas Series 物件, 否則繪圖時會出現錯誤. 由於 ta 指標計算方法傳回的是 Series 物件, 所以要用 values 屬性取得 ndarray 物件後作為 y1 與 y2 鍵之值. 

先在 K 線圖上新增布林傑上下限與中線疊圖 :

>>> import kbar   
>>> kb=kbar.KBar(df)    
>>> kb.addplot(bbh, color='red', width=1)       # 上限疊圖
>>> kb.addplot(bbm, color='blue', width=1)     # 中線疊圖  
>>> kb.addplot(bbl, color='green', width=1)     # 下限疊圖

然後建立一個填色字典 : 

>>> fill_between=dict(y1=bbl.values, y2=bbh.values, color='cyan', alpha=0.3)   

這裡 y1 與 y2 參數都是用 values 屬性從 bbl (下限) 與 bbh (上限) 這兩個 Series 物件中取出的一維 ndarray 陣列 : 

>>> bbl.values   
array([         nan,          nan,          nan,          nan,
                nan,          nan,          nan,          nan,
                nan,          nan,          nan,          nan,
                nan,          nan,          nan,          nan,
                nan,          nan,          nan, 170.12689033,
       170.23572968, 170.28583699, 170.20918148, 170.08403056,
       169.81666464, 169.25048449, 168.61944645, 168.16900744,
       168.14925903, 168.15729205, 168.20390841, 169.19939766,
       170.27416137, 170.95175947, 172.13770519, 173.60905758,
       175.1146881 , 175.86193223, 176.77859139, 177.31671369,
       178.45402917, 179.47429228, 180.35475564, 181.30589677,
       181.99071414, 182.36593703, 182.54719321, 182.79797247,
       183.86675428, 185.35692943, 187.1846761 , 187.98999251,
       189.12906253, 189.84455446, 190.01109833, 190.23275395,
       189.96888795, 189.63812581, 189.51609843, 188.84458977,
       188.72614331, 188.50619393, 187.92008835, 187.85801194,
       187.80223999, 187.4549489 , 186.69404511, 185.91857966,
       185.41537725, 185.35391702, 185.35463013, 185.34540622,
       185.42701563, 185.77766063, 186.19018768, 186.17159865,
       186.1747256 , 186.24260036, 186.23718512, 186.4806345 ,
       186.43269043, 186.50360361, 186.97686189, 186.94599184,
       187.0024802 , 187.40804458, 188.53739771, 190.08511692,
       191.92075606, 192.61908143, 192.78440713, 192.60245912,
       192.58255969, 192.01177644, 191.21332298, 191.31273806,
       191.90515682, 192.16284683, 192.02767806, 191.97167638,
       191.62230933, 191.6654256 , 191.9038928 ])
>>> bbh.values   
array([         nan,          nan,          nan,          nan,
                nan,          nan,          nan,          nan,
                nan,          nan,          nan,          nan,
                nan,          nan,          nan,          nan,
                nan,          nan,          nan, 186.35311303,
       185.65427429, 185.43916606, 185.67582066, 186.03097188,
       186.6733378 , 187.96951825, 189.2305566 , 190.520995  ,
       190.80074249, 191.06770947, 191.37609342, 192.07060356,
       192.49083955, 193.23824145, 194.06229481, 194.58594211,
       195.53531037, 196.25806593, 196.83140769, 198.228286  ,
       199.11097022, 199.80570803, 200.28024497, 200.48410415,
       200.93928616, 201.39406358, 201.4328071 , 201.47202875,
       201.05824724, 200.50307118, 199.68032329, 199.58000719,
       199.46093686, 199.74544493, 200.27390228, 200.22224635,
       200.12111296, 200.2518751 , 200.27890279, 200.10541023,
       199.64385638, 199.27880516, 199.19991134, 199.08698775,
       198.73776093, 198.46505232, 198.78595672, 199.06142217,
       199.23962458, 199.17608481, 199.24037261, 199.27459652,
       199.09798742, 198.42234243, 197.69981476, 197.77840441,
       197.79027684, 198.13740147, 198.4378164 , 198.83936825,
       199.37231293, 199.86640066, 199.89814116, 199.88401151,
       200.31752255, 200.70695786, 200.70760351, 200.30488399,
       199.63424424, 199.54591948, 199.52559348, 199.5675421 ,
       199.53744153, 200.74822417, 202.38667702, 202.96226194,
       202.98484409, 203.1121547 , 203.15732255, 203.16332423,
       203.21269128, 203.2645747 , 203.21610842])

然後將此填色字典傳給 plot() 函式的 fill_between 參數即可 :

>>> kb.plot(volume=True, fill_between=fill_between)

結果如下 : 



蝦皮購買數位電視機上盒 DVB-T2

周一中午與爸通電話時得知鄉下餐廳的電視顯示無訊號, 可能是機上盒故障, 在蝦皮找到一款最新款的 : 






含運 740+60 共 800 元, 7-11 志興店取貨付款, 預計 1/24 週五到貨. 

本來想在露天買的, 價格較便宜且免運, 但賣家對於詢問均未回覆只好算了 :


台灣傳奇這家有說明掃描頻道時要把語言設為西班牙語, 國家選古巴或哥倫比亞, 然後選 Auto scan 就可以找到全部頻道. 


2025-01-24 補充 :

晚上帶回鄉下檢視舊機器 LED 顯示異常, 應該是機子故障, 於是立馬裝上新的, 測試可正常使用. 

2025年1月20日 星期一

Python 學習筆記 : 如何在 K 線圖上標記買賣信號

在之前的量化投資測試中, 使用了基於 mplfinance 的 kbar.py 模組來簡化 K 線圖之繪製, 但只是用 mav 參數或自行計算之 SMA 指標在 K 線圖上疊圖而已, 本篇要來測試如何在 K 線圖上打上標記, 例如在最常見的雙均線交叉策略中於黃金交叉點打上一個向上三角形 ▲ 標示買點; 而在死亡交叉處打上向下三角形 ▼ 標示賣點. 

本系列之前的文章參考 : 


K 線圖繪製模組 kbar.py 原始碼如下 :

# kbar.py
import mplfinance as mpf

class KBar():
    def __init__(self, df):
        self.df=df
        self.addplots=[]
    def addplot(self, data, **kwargs):
        plot=mpf.make_addplot(data, **kwargs)
        self.addplots.append(plot)
    def plot(self, embedding=False, **kwargs):
        color=mpf.make_marketcolors(up='red', down='green', inherit=True)   
        font={'font.family': 'Microsoft JhengHei'}   
        style=mpf.make_mpf_style(base_mpf_style='default',
                                 marketcolors=color,
                                 rc=font)
        kwargs['type']='candle'
        kwargs['style']=style
        kwargs['addplot']=self.addplots
        if 'returnfig' in kwargs and kwargs['returnfig'] is True:
            fig, axes=mpf.plot(self.df, **kwargs)
            return fig, axes
        else:
            mpf.plot(self.df, **kwargs)

首先匯入本篇測試要用到的模組 : 

>>> import kbar    
>>> import yfinance as yf   
>>> import ta   

從 yfinance 下載價量資料 :

>>> df=yf.download('0050.TW', start='2024-10-20', end='2025-01-20')   
[*********************100%%**********************]  1 of 1 completed   

用 ta 套件計算長短天期 SMA 指標, 長短天期是相對的概念, 跨度因人而異, 此處取 5 日 (周線) 為短天期, 20 日 (月線) 為長天期. 

呼叫 ta 的 SMA 指標類別建構式 SMAIndicator() 建立指標物件 : 

>>> SMA5=ta.trend.SMAIndicator(df['Close'], window=5)      # 短天期均線
>>> SMA20=ta.trend.SMAIndicator(df['Close'], window=20)   # 短天期均線

呼叫指標物件之 sma_indicator() 方法計算 SMA 指標 : 

>>> sma5=SMA5.sma_indicator()   
>>> sma20=SMA20.sma_indicator()    

然後建立 KBar 物件來繪製 K 線圖 : 

>>> kb=kbar.KBar(df)   

呼叫 KBar 物件的 addplot() 方法建立疊圖 (預設 panel=0 為疊圖)

>>> kb.addplot(sma5, color='blue', width=1)       # 疊圖 1
>>> kb.addplot(sma20, color='black', width=1)   # 疊圖 2

最後呼叫 KBar 物件的 plot() 方法繪製 K 線圖 :

>>> kb.plot(volume=True)    # 顯示成交量

結果如下 :




此雙均線交易策略顯示在過去三個月中至少出現一次黃金交叉的買入訊號與一次死亡交叉的賣出信號, 我們的目標是要在此 K 線圖上用 ▲ 與 ▼ 標示買賣點. 

首先偵測黃金交叉點, 即短天期均線 sma5 向上突破長天期均線 sma20 (大於), 且前一天 shift(1) 尚未向上突破 (小於或等於) :

>>> golden_cross=(sma5 > sma20) & (sma5.shift(1) <= sma20.shift(1))    
>>> golden_cross   
Date
2024-10-21    False
2024-10-22    False
2024-10-23    False
2024-10-24    False
2024-10-25    False
              ...  
2025-01-13    False
2025-01-14    False
2025-01-15    False
2025-01-16    False
2025-01-17    False
Length: 63, dtype: bool

其次偵測死亡交叉點, 即短天期均線 sma5 向下跌破長天期均線 sma20 (小於), 且前一天 shift(1) 尚未跌破 (大於或等於) :

>>> death_cross=(sma5 < sma20) & (sma5.shift(1) >= sma20.shift(1))  
>>> death_cross  
Date
2024-10-21    False
2024-10-22    False
2024-10-23    False
2024-10-24    False
2024-10-25    False
              ...  
2025-01-13    False
2025-01-14    False
2025-01-15     True
2025-01-16    False
2025-01-17    False
Length: 63, dtype: bool

我們用此兩個布林 Series 去選取收盤價 (也可以是開盤價) 會得到一個子 Series : 

>>> df['Close'][golden_cross]   
Date
2024-12-05    196.5
Name: Close, dtype: float64
>>> df['Close'][death_cross]       
Date
2025-01-15    194.100006
Name: Close, dtype: float64

可見符合黃金與死亡交叉條件的交易日都各只有一個, 如果要在這兩點上打上標記, 就必須用一個與 K 線圖等長的 Series 來疊圖, 而此 Series 僅在上面兩處有值, 其餘日期為 NaN, 方法是將這兩個子 Series 傳給 pd.Series() 且傳入 index=df.index 確保索引與 df 一致, 這樣就可以將這兩個子 Series 拉長到與 df 一樣長才能疊圖 : 

>>> golden_cross_points=pd.Series(df['Close'][golden_cross], index=df.index)   
>>> death_cross_points=pd.Series(df['Close'][death_cross], index=df.index)       

檢視拉長後的 Series : 

>>> golden_cross_points   
Date
2024-10-21   NaN
2024-10-22   NaN
2024-10-23   NaN
2024-10-24   NaN
2024-10-25   NaN
              ..
2025-01-13   NaN
2025-01-14   NaN
2025-01-15   NaN
2025-01-16   NaN
2025-01-17   NaN
Name: Close, Length: 63, dtype: float64
>>> death_cross_points   
Date
2024-10-21           NaN
2024-10-22           NaN
2024-10-23           NaN
2024-10-24           NaN
2024-10-25           NaN
                 ...    
2025-01-13           NaN
2025-01-14           NaN
2025-01-15    194.100006
2025-01-16           NaN
2025-01-17           NaN
Name: Close, Length: 63, dtype: float64

這樣就可以用這兩個 Series 來繪製疊圖以標記買賣點了 : 

>>> kb.addplot(golden_cross_points, scatter=True, markersize=50, marker='^', color='blue', label='Golden Cross')   
>>> kb.addplot(death_cross_points, scatter=True, markersize=50, marker='v', color='black', label='Death Cross')   
>>> kb.plot(volume=True)    

結果如下 :




不過從這張圖來看, 此策略在此似乎是虧錢啊! 以月線當長天期反應時間較慢, 等賣出信號出現股價已經跌一段了.  

2025 年第 3 周記事

感覺才剛跨年哩, 2025 卻已過去三周矣. 這禮拜週二週三請假辦理吾妹阿蘭安金事宜, 所以本周我只上班三天. 週二主要是先回鄉下將應準備之祭品都買齊, 早上先去墓園再打掃一遍, 又去鎮上鮮花店買一對鮮花, 下午去觀音廟先將阿蘭金罐遷出暫放在墓園右側. 傍晚出去高雄載小狐狸們與水某返回鄉下, 這樣周三早上就不會太趕. 還好有再三確認使程序都順利完成. 接下來是滿 12 天 (1/26 下周日) 要準備水果三份 (含后土與天神) 去墓園奉茶, 上香, 與燒金, 滿一個月 (2/13 週四) 要準備五牲, 發粄紅粄各三包, 水果三份, 鮮花一對, 防風燭三對, 鞭炮一串, 酒, 金, 香, 茶去祭拜才圓滿整個安金過程. 

最近兩周寒流報到, 白天雖有陽光但早晚非常冷, 我光是睡袋還不行, 裡面還鋪一層毛毯才夠暖, 過去幾年都是暖冬, 今年不知為何突然變得異常地冷. 鄉下家養的貓趁著白天陽光露臉, 幾兄弟姊妹我在一起做日光浴, 它們的貓生過得可滋潤哩 ! 




最近又開始看戲了, 韓劇魷魚遊戲 2 已上線, 我目前看到第二集; 週六看了一部泰國片 "金孫爆富攻略", 描寫一個泰國華裔家庭 (潮州人) 中本來很廢的外孫為了能繼承房產去照顧罹癌外婆, 雖然外婆最終將房子給了二舅, 但他卻在此過程中找回真心與親情的感人故事. 

用 ChatGPT 依照指定格式產生 Blogger 表格

我在 Blogger 喜歡用以前舊版協作平台網頁編輯器所使用的表格來呈現資料, 舊版走入歷史時我有記下其 HTML 原始碼紀錄在下面這篇 :


不過每次都要從那邊複製一張空表格來填很費時間, 最近在寫量化投資測試筆記時嘗試改用 ChatGPT 來幫我做這件有點小累累的苦工感覺效率倍增, 因為連內容都幫我填好了, 我只要核對資料是否正確即可,  AI 真是太省時省力啦! 

以這兩天製作 mplfinance 套件的 plot() 函式有哪些參數的表格為例, 提示詞如下 : 

mplfinance 的 plot() 函式有哪些參數? 請用下列的表格格式呈現, 文字內容都使用半型字體, 英文或數字等與前後的中文字之間要留一個空格, 括弧則僅前後留一個空格即可, 與其內容之間不必留空格, 產生的 HTML 碼格式要排列整齊 :

<table border="1" bordercolor="#888" cellspacing="0" style="background-color: white; border-collapse: collapse; border-color: rgb(136, 136, 136); border-width: 1px; color: #534741; font-family: Arial, Verdana, sans-serif; font-size: 13.3333px; margin: 0px;">
  <tbody>
    <tr>
      <td style="width: 189.011px; padding: 3px;">&nbsp;參數名稱</td>
      <td style="width: 402.011px; padding: 3px;">&nbsp;說明</td>
    </tr>
    <tr>
      <td style="padding: 3px;">&nbsp;</td>
      <td style="padding: 3px;">&nbsp;</td>
    </tr>
  </tbody>
</table>


按 "複製程式碼" 鈕, 到 Blogger 切換至 HTML 模式, 將表格內容貼上, 然後再檢查內容正確性與微調格式即可. 以前花太多時間填表格, 難怪整理筆記的根本龜速, 現在有 ChatGPT 協助宛如吃了大力丸. 上面提示詞就記下來當範本. 

2025年1月19日 星期日

博客來買書兩本 : ChatGPT 萬用手冊 2025 春季號+AI 自動化流程超 Easy

晚上滑臉書看到博客來今日有下面兩書合購 66 折優惠, 當即下單買了 : 







合計 898 元折抵 Open Point 17 元, 實付 881 元 (小七至興店取貨付款). 

Python 學習筆記 : 技術指標的計算與視覺化摘要

在初步掌握 Ta-Lib 與 ta 這兩個技術指標套件基本用法後, 接下來想要使用這兩個套件測試一些常用指標, 先將這兩個指標套件的用法整理如下. 

本系列測試主要是利用 yfinance 作為盤後資料來源, 它不需要申請 API Key 即可直接下載價量資料, 例如 :

import yfinance as yf 
df=yf.download('0050.TW', start='2024-11-06', end='2025-01-09')

參考 :


也可以從 FinMind 或 FinLab API 取得股票盤後資料 (需先註冊取得 API Key), 參考 :


關於使用 Ta-Lib 與 ta 計算技術指標的方法參考 :



更多測試文章參考 :



1. TA-Lib 與 ta 之比較 : 

這兩個技術指標套件在各面向之比較如下表 : 


 面向  ta 套件  TA-Lib 套件
指標支援度 提供 80 種技術指標, 包括趨勢, 動能, 波動, 量能等類型. 支援部分較新的指標 (如 STC, KAMA 等). 提供超過 158 種技術指標, 涵蓋絕大部分經典指標 (例如 RSI, MACD, Bollinger Bands), 但不支援較新的或自定義指標.
運算速度 基於純 Python 開發, 運算速度相對較慢,尤其是大型資料集, 適合小型至中型資料集分析. 底層使用 C 語言實作, 運算速度非常快, 對大型資料集有優勢.
Pandas 支援 與 Pandas 深度整合, 輸入與輸出均為 Pandas DataFrame 或 Series, 方便與其他分析工具鏈結.   主要以 NumPy 為核心, 輸入與輸出為 NumPy ndarray 陣列, 但需手動整合 Pandas, 對新手較不直覺. 
API 使用方便性 提供物件導向和函數式 API, 呼叫直覺簡單, 適合快速添加指標欄位到 Pandas DataFrame 中, 支援批次添加指標. API 偏向函數式, 對於個別指標的計算較直觀, 但缺乏批次計算與添加至欄位功能, 需自行管理多次呼叫的邏輯.
安裝與相容性完全基於 Python, 安裝簡單 (用 pip install 即可), 不依賴額外的編譯工具, 適合所有平台. Linux 平台需要編譯 C 程式碼, Windows 平台需要搭配 Python 版本下載 whl 檔安裝, 對於非技術用戶安裝略有挑戰.
擴展性開放原始碼且基於 Python, 易於修改與擴展, 可自定義新指標. 雖然是開放原始碼, 但因為基於 C 實現, 擴展性相對較低, 需精通 C 語言才能進行修改. 
適用場景 適合對 Pandas 資料集進行快速技術分析, 對於中小型資料處理更友好. 適合高效處理大型資料集, 對於需要高運算性能的場景(如高頻交易模擬)更具優勢.


簡言之, Ta-Lib 底層是 C 語言實作且基於 Numpy 運算速度快, 而 ta 則是原生 Python 實作, 雖然速度較慢但提供自訂指標功能, 具有彈性大靈活度高優勢. 


2. 價量資料欄位名稱之調整 : 

使用 Ta-Lib 物件導向 API 計算指標時, 傳入的價量資料 DataFrame 之欄位名稱必須是全小寫, 如果價量資料來自 yfinance 可用下面這個串列生成式修改欄位名稱 :

df.columns=[column.lower() for column in df.columns] 

若價量資料來自 FinMind 可用 DataFrame 的 rename() 方法修改修改欄位名稱 : 

df=df.rename(columns={'max': 'High', 'min': 'Low', 'Trading_Volume': 'volume'})  

但使用 ta 套件計算指標則毋須對 DataFrame 的價量欄位名稱做任何修改, 因為 ta 套件的 API 是用參數指定價量欄位名稱的方式來處理, 這樣較有彈性. 


3. Ta-Lib 的用法摘要 : 

Ta-Lib 套件的函數式 API 因為價量資料需使用 Numpy ndarray, 使用起來較麻煩些, 而其物件導向 API 則支援 Pandas DataFrame 較方便好用, 故通常使用物件導向 API, 用法摘要如下 : 

先匯入要用到的指標類別 : 

from talib.abstract import RSI, OBV, MFI  

或者匯入全部類別 : 

from talib.abstract import *

然後呼叫類別之建構式並傳入價量資料之 DataFrame 就會傳回計算結果 (Series 物件) :

rsi=RSI(df)   # 計算 RSI 指標
obv=OBV(df)   # 計算 OBV 指標
mfi=MFI(df)   # 計算 MFI 指標

可傳入其他關鍵字參數 (例如 timeperiod, 如果有的話, 因為像 MFI 即無此參數) :

rsi=RSI(df, timeperiod=5)

呼叫 print(指標類別) 或 help() 可查詢該類別之 API 介面 (即建構式有哪些參數) :

print(RSI)
help(RSI)


4. ta 的用法摘要 : 

首先匯入 ta :

import ta

ta 的技術指標計算可使用函數式或物件導向式兩種 API, 可視需求呼叫指標函式, 或呼叫指標類別建構式建立物件後再呼叫其方法計算指標, 傳回值都是一個 Series 物件. 

ta 的函數式用法特色是提供可一次產生所有指標數據之快捷函式, 如下表所示 : 


 ta 的快捷函式 說明
 add_all_ta_features()  計算所有支援的技術指標後添加到 DataFrame 中. 傳入參數 : 
 df (必要之位置參數): 不含 NaN 值的價量 DatFrame
 open, high, low, close, volume (關鍵字參數) : OHLCV 價量欄位名稱
 fillna (關鍵字參數) : 是否以預設值填充 NaN, True/False (預設)
 傳回值 : 添加技術指標欄位值後的 DataFrame
 add_momentum_ta() 添加動能類技術指標 (例如 RSI, MACD 等) 到 DataFrame. 傳入參數 : 
 df (必要之位置參數): 不含 NaN 值的價量 DatFrame
 close, volume (關鍵字參數) : 收盤價, 成交量欄位名稱
 fillna (關鍵字參數) : 是否以預設值填充 NaN, True/False (預設)
 傳回值 : 添加動能類技術指標欄位值後的 DataFrame
 add_others_ta() 添加其他類技術指標 (例如每日報酬率與波動率等) 到 DataFrame. 
 傳入參數 : 
 df (必要之位置參數): 不含 NaN 值的價量 DatFrame
 close (關鍵字參數) : 開盤價欄位名稱
 fillna (關鍵字參數) : 是否以預設值填充 NaN, True/False (預設)
 傳回值 : 添加其他類技術指標欄位值後的 DataFrame
 add_trend_ta() 添加趨勢類技術指標 (例如移動平均線, ADX) 到 DataFrame. 傳入參數 :
 df (必要之位置參數): 不含 NaN 值的價量 DatFrame
 high, low, close (關鍵字參數) : 最高價, 最低價, 收盤價之欄位名稱
 fillna (關鍵字參數) : 是否以預設值填充 NaN, True/False (預設)
 傳回值 : 添加趨勢類技術指標欄位值後的 DataFrame
 add_volatility_ta() 添加波動類技術指標 (例如布林通道) 到 DataFrame. 傳入參數 :
 df (必要之位置參數): 不含 NaN 值的價量 DatFrame
 high, low, close (關鍵字參數) : 最高價, 最低價, 收盤價之欄位名稱
 fillna (關鍵字參數) : 是否以預設值填充 NaN, True/False (預設)
 傳回值 : 添加動能類技術指標欄位值後的 DataFrame
 add_volume_ta() 添加量能類技術指標 (例如 OBV) 到 DataFrame. 傳入參數 :
 high, low, close, volume (關鍵字參數) : OHLCV 價量欄位名稱
 fillna (關鍵字參數) : 是否以預設值填充 NaN, True/False (預設)
 傳回值 : 添加技術指標欄位值後的 DataFrame


直接呼叫這些快捷函式並傳入 DataFrame 就會將計算結果增添到 DataFrame 欄位中 (使用參數之預設值計算), 傳回值就是增添欄位後的 DataFrame, 例如 :

ta.add_all_ta_features(df)

使用 ta 指標類別前須先查詢其 API, 確認呼叫其建構式時須傳入之參數, 每個指標需要傳入之 OHLCV 參數不同, 例如 OBV 需要傳入收盤價與成交量 :

OBV=ta.volume.OnBalanceVolumeIndicator(close=df['Close'], volume= df['Volume']) 

建立物件後呼叫其指標計算方法即可取得指標數據, 例如 :

obv=OBV.on_balance_volume() 

而 RSI 指標則只要傳入收盤價 :

RSI=ta.momentum.RSIIndicator(close=df['Close'])
rsi=RSI.rsi() 

除了必要的 OHLCV 參數外, 也可傳入其他關鍵字參數例如移動窗口 window 或 fillna 等來更改預設值, 每個指標的參數結構均不同, 可查閱官網教學文件來確認 :


也可以用 help() 在命令列查詢, 例如 :

help(ta.volume.OnBalanceVolumeIndicator)


5. 繪製 K 線圖與指標視覺化 : 

計算出指標數值後可以用 mplfinance 套件繪製 K 線圖與指標附圖以便將其視覺化, 我寫了一個自訂模組 kbar.py 來簡化此過程 : 

# kbar.py
import mplfinance as mpf

class KBar():
    def __init__(self, df):
        self.df=df
        self.addplots=[]
    def addplot(self, data, **kwargs):
        plot=mpf.make_addplot(data, **kwargs)
        self.addplots.append(plot)
    def plot(self, embedding=False, **kwargs):
        color=mpf.make_marketcolors(up='red', down='green', inherit=True)   
        font={'font.family': 'Microsoft JhengHei'}   
        style=mpf.make_mpf_style(base_mpf_style='default',
                                 marketcolors=color,
                                 rc=font)
        kwargs['type']='candle'
        kwargs['style']=style
        kwargs['addplot']=self.addplots
        if 'returnfig' in kwargs and kwargs['returnfig'] is True:
            fig, axes=mpf.plot(self.df, **kwargs)
            return fig, axes
        else:
            mpf.plot(self.df, **kwargs)

使用 kbar.py 繪製 K 線圖方法基本上只要三行指令 :

import kbar  # 匯入模組
kb=kbar.KBar(df)  # 傳入價量 DataFrame
kb.plot(volume=True, mav=[3, 5, 10])  # 繪製 K 線圖 + 成交量副圖 + 3/5/10 日均線疊圖 

如果要繪製技術指標副圖, 則可先呼叫 KBar 物件的 addplot() 方法傳入指標 Series 物件, 最後再呼叫 plot() 方法 :

kb.addplot(rsi, panel=2, ylabel='RSI)
kb.addplot(obv, panel=3, ylabel='OBV') 
kb.addplot(mfi, panel=4, ylabel='MFI')
kb.plot(volume=True, mav=5)  # 繪製 K 線圖 + 成交量副圖 + 5 日均線疊圖

因為疊圖固定使用 panel=0, 成交量固定使用 panel=1, 因此技術指標副圖最好從 panel=2 開始依序指定. 可以在呼叫 addplot() 時傳入下列參數修改副圖屬性 :


addplot() 方法參數 說明
data 要繪製的一維資料 : Pandas Series 或 NumPy Array (必要參數)
scatter 是否繪製散點圖 : True 或 False, 預設 False
type 繪圖類型 : 'line' (折線圖) 或 'bar' (長條圖), 預設為 'line'
color 線條或標記的顏色 : 可用顏色名稱例如 'red' 或 HEX 例如 '#00ff00'
alpha 透明度 : 範圍為 0 (完全透明) 到 1 (完全不透明) 之浮點數
linestyle 線條樣式 : 例如 '-'、'--'、'-.' 或 ':' 等
width 線條寬度 : 整數 (單位 px)
markersize 標記點的大小 : 整數, 僅對 scatter=True 有效
marker 資料點標記符號,  : 例如 'o' (圓點),  's' (方點),  'x' (叉叉), '^' (上三角) 等
panel 繪圖框編號 (0~9, 0 為疊圖, 1~9 為副圖, 但 1 為內建成交量副圖)
ylabel 面板 Y 軸的標籤文字
ylim Y 軸座標範圍 (串列)


如果要設定整張 K 線圖屬性 (例如標題) 可在呼叫 plot() 方法時傳入下列參數 :


plot() 方法參數 說明
mav 設定均線日期, 可以是整數 (單天期均線) 或整數串列 (多天期均線)
volume 是否顯示成交量副圖 : True 或 False, 預設 False
show_nontrading 是否顯示非交易日 : True 或 False, 預設 False
figscale 圖形縮放比率 (在 figratio 尺寸基礎上進行縮放)
figratio 圖形寬高尺寸比例, 可用 tuple (寬, 高) 或 list [寬, 高], 預設 (8, 5.75) 吋
title 設定圖形標題
ylabel 主圖表的 Y 軸標籤
ylabel_lower 次圖表 (例如成交量) 的 Y 軸標籤
xrotation X 軸標籤旋轉角度 (預設 45)
savefig 設定欲儲存之圖檔路徑與檔名 (支援 jpg, png, pdf, 與 svg)
tight_layout 是否以緊緻方式排版 : True 或 False, 預設 False
block 是否直接繪圖 : True 或 False, 預設 True. 若為 False 須用 plt.show() 繪圖
returnfig 是否傳回 Figure 物件 : True 或 False, 預設 False


如果要將 kbar.py 繪製的 K 線圖嵌入到 Gradio/Sreamlit 等 Web app 應用中時, 須傳入 returnfig=True, 這樣 plot() 會傳回一個 Figure 物件, 將此物件傳給 Gradio.Plot() 或 Streamlit.pyplot() 即可將所繪製的 K 線圖嵌入 Web app 網頁中.  


2025-01-23 補充 :

kbar.py 已改版為在 returnfig=True 時傳回 (fig, axes) 元組 (原本僅傳回其中的 Figure 物件), 已更新上面的原始碼. 

2025年1月18日 星期六

Python 學習筆記 : 技術指標套件 ta 用法 (二)

由於篇幅過長, 因此將 ta 的物件導向 API 用法紀錄在此續篇, 本系列前一篇文章參考 : 



2. ta 的物件導向式 API :      

如前所述, ta 套件的指標類別都分別放在 trend, volatility, volume, momentum, 與 others 等五大指標類型模組下, 使用物件導向 API 時須呼叫指標類別的建構式並傳入價量資料的 DataFrame 以建立一個指標類別, 然後須呼叫其方法才能取得指標數據. 

ta 原生支援 Pandas, 以下測試使用最方便的 yfinance 取得股票之價量資料, 因為 yfinance 就是直接傳回股票價量資料的 DataFrame 且毋須傳遞 API Key. 以台灣五十 (0050) 為例 : 

>>> df=yf.download('0050.TW', start='2024-11-06', end='2025-01-09')   
[*********************100%%**********************]  1 of 1 completed
>>> df.columns     
Index(['Open', 'High', 'Low', 'Close', 'Adj Close', 'Volume'], dtype='object')

以 OBV 指標為例, 其指標類別為 ta.volume.OnBalanceVolumeIndicator :




呼叫建構式 OnBalanceVolumeIndicator() 時必須傳入 close 與 volume 這兩個必要參數, 它會傳回一個 OnBalanceVolumeIndicator 物件 : 

>>> OBV=ta.volume.OnBalanceVolumeIndicator(close=df['Close'], volume= df['Volume'])   
>>> type(OBV)   
<class 'ta.volume.OnBalanceVolumeIndicator'>   

傳回物件只有一個公開方法 on_balance_volume(), 呼叫它會傳回計算出來的 OBV 指標數據 (型態為 Series 物件) : 

>>> obv=OBV.on_balance_volume()   
>>> obv     
Date
2024-11-06    16706376
2024-11-07    30204928
2024-11-08    43155079
2024-11-11    55519092
2024-11-12    29247005
2024-11-13    20052415
2024-11-14     7905800
2024-11-15    15291381
2024-11-18     1896865
2024-11-19     9515186
2024-11-20     9437186
2024-11-21    -6439431
2024-11-22     1526156
2024-11-25    -6300507
2024-11-26   -17691329
2024-11-27   -31764015
2024-11-28   -44873129
2024-11-29   -36744909
2024-12-02   -26200831
2024-12-03   -16247725
2024-12-04    -9792476
2024-12-05    -2346273
2024-12-06    -9155779
2024-12-09    -4515915
2024-12-10    -8993222
2024-12-11   -15707911
2024-12-12   -10680670
2024-12-13    -6160243
2024-12-16     1183349
2024-12-17    10477578
2024-12-18    17031455
2024-12-19     3986408
2024-12-20    -7136986
2024-12-23     4039080
2024-12-24    12234982
2024-12-25    18141105
2024-12-26    13337544
2024-12-27    20324961
2024-12-30    11647695
2024-12-31     3811161
2025-01-02    -8986541
2025-01-03    -1873170
2025-01-06    22754623
2025-01-07    38698467
2025-01-08    26842750
Name: obv, dtype: int64

此結果與使用指標函式 ta.volume.on_balance_volume() 得到的數據是一樣的. 

接下來計算動能類型的 RSI 指標, 其指標類別為 ta.momentum.RSIIndicator




RSI 為相對強弱指標, 用於衡量價格是在超買或超賣狀態, 從 API 可知必要參數為 close 收盤價 (Series 物件), 備選參數 window 用來設定移動窗口 (預設 14), fillna 設定是否要對 NaN 做填入動作 (預設 False). 呼叫 ta.momentum.RSIIndicator() 並傳入參數建立 RSIIndicator 物件 :

>>> RSI=ta.momentum.RSIIndicator(close=df['Close'])   
>>> type(RSI)   
<class 'ta.momentum.RSIIndicator'>   

RSIIndicator 物件只有一個公開方法 rsi(), 呼叫 rsi() 會傳回計算出來的 RSI 指標數據 :

>>> rsi=RSI.rsi()   
>>> rsi   
Date
2024-11-06          NaN
2024-11-07          NaN
2024-11-08          NaN
2024-11-11          NaN
2024-11-12          NaN
2024-11-13          NaN
2024-11-14          NaN
2024-11-15          NaN
2024-11-18          NaN
2024-11-19          NaN
2024-11-20          NaN
2024-11-21          NaN
2024-11-22          NaN
2024-11-25    45.732159
2024-11-26    39.560536
2024-11-27    34.107863
2024-11-28    33.564358
2024-11-29    35.231532
2024-12-02    48.890462
2024-12-03    54.877909
2024-12-04    57.262711
2024-12-05    59.373997
2024-12-06    57.200326
2024-12-09    57.755502
2024-12-10    53.565209
2024-12-11    48.923488
2024-12-12    54.538551
2024-12-13    54.894578
2024-12-16    56.835996
2024-12-17    59.199976
2024-12-18    59.199976
2024-12-19    50.533601
2024-12-20    45.727610
2024-12-23    57.082949
2024-12-24    58.197052
2024-12-25    59.434195
2024-12-26    58.964392
2024-12-27    60.424311
2024-12-30    56.745051
2024-12-31    50.565547
2025-01-02    46.083754
2025-01-03    51.404401
2025-01-06    63.603546
2025-01-07    66.879390
2025-01-08    59.112553
Name: rsi, dtype: float64

最後利用 mplfinance 套件來繪製 K 線圖與上面的指標, 我寫了一個基於 mplfinance 的 kbar.py 模組來簡化 K 線圖的繪製 :

# kbar.py
import mplfinance as mpf

class KBar():
    def __init__(self, df):
        self.df=df
        self.addplots=[]
    def addplot(self, data, **kwargs):
        plot=mpf.make_addplot(data, **kwargs)
        self.addplots.append(plot)
    def plot(self, embedding=False, **kwargs):
        color=mpf.make_marketcolors(up='red', down='green', inherit=True)   
        font={'font.family': 'Microsoft JhengHei'}   
        style=mpf.make_mpf_style(base_mpf_style='default',
                                 marketcolors=color,
                                 rc=font)
        kwargs['type']='candle'
        kwargs['style']=style
        kwargs['addplot']=self.addplots
        if 'returnfig' in kwargs and kwargs['returnfig'] is True:
            fig, axes=mpf.plot(self.df, **kwargs)
            return fig, axes
        else:
            mpf.plot(self.df, **kwargs)

匯入 kbar 模組並呼叫 kbar.KBar() 建構式建立一個 KBar 物件, 然後把 OBV 與 RSI 指標分別畫在 副圖 2 與副圖 3 (因為成交量固定占用副圖 1) : 

>>> import kbar     
>>> kb=kbar.KBar(df)    
>>> kb.addplot(obv, panel=2, ylabel='OBV')    # 副圖 2
>>> kb.addplot(rsi, panel=3, ylabel='RSI')      # 副圖 3
>>> kb.plot(volume=True, mav=5)  

結果如下 :