2025年1月19日 星期日

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, ax=mpf.plot(self.df, **kwargs)
            return fig
        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 網頁中.  

沒有留言 :