本篇旨在測試如何用 pandas-ta 套件計算技術指標 (以 RSI 為例) 並繪製 K 線圖.
本系列全部文章索引參考 :
5. 技術指標函式用法 :
pandas-ta 技術指標函式有兩種呼叫方式 :
- 直接呼叫指標函式 : 例如 ta.rsi()
- 透過 DataFrame 的擴展屬性 ta 呼叫 : 例如 df.ta.rsi()
這兩種方式的傳入參數, 傳回值, 與適用情境不同, 摘要如下表 :
| 呼叫方式 | 說明 |
|---|---|
| df.ta.xxx() | 傳入參數 : 共通參數 + 指標特有參數, 未傳入 OHLCV 時會自動抓 DataFrame 欄位 回傳值 : Series (單欄輸出) 或 DataFrame (多欄輸出) 計算結果會自動加回原 DataFrame 欄位 (傳入 append=True 時, 此為預設) 適用情境 : 直接對 DataFrame 計算指標, 適合指標批量計算 |
| ta.xxx() | 傳入參數 : 計算指標所需之 OHLCV 價量資料欄位 (Series) + 指標特有參數 回傳值 : Series (單欄輸出) 或 DataFrame (多欄輸出) 適用情境 : 直接呼叫函式計算指標值, 傳回 Series (單欄輸出) 或 DataFrame (多欄輸出), 適合單一 Series 或自定義策略計算, 靈活度高 |
當我們用 import pandas_ta as ta 匯入 pandas-ta 套件時, 它會在背後自動對 pandas.DataFrame 類別做 monkey patch (動態修改/擴充/覆寫現有模組/類別/物件的作法, 毋須修改 Pandas 原始碼), 具體而言是在 DataFrame 類別上添加一個 ta 屬性 (稱為擴展屬性), 這個 ta 屬性的值是一個封裝了所有指標函式的介面物件 (自訂的 Accessor), 它內部會把呼叫 xxx() 方法映射到 pandas-ta 的 xxx() 指標函式, 因此任何現有或新建的 DataFrame 都可以直接用 df.ta.xxx() 來呼叫這些指標函式. 這種作法常用於在不更改套件原始碼情況下擴充功能或修補 bug.
使用 df.ta.xxx() 計算指標時, pandas-ta 會自動從 DataFrame 中選擇計算該指標所需的欄位, 毋須明確傳入 close, high, low, close, volumn 等價量參數來指定欄位來源, pandas-ta 會自動在 DataFrame 裡搜尋各種可識別的欄名 (內部使用正規式模糊比對, 大小寫不敏感), 下列是可自動識別的 OHLCV 欄名 :
- "open", "high", "low", "close", "volume"
- "Open", "High", "Low", "Close", "Volume"
- "O", "H", "L", "C", "V"
- "o", "h", "l", "c", "v"
- "o", "h", "lo", "cl", "vol"
如果欄位名稱相似, 例如有 Adj Close 與 Close 兩個欄位, 則 pandas-ta 內部有一個優先順序表, 第一個欄位會被拿來做計算 :
| 類別 | 欄位名稱優先順序 |
|---|---|
| Open | "open", "Open" |
| High | "high", "High" |
| Low | "low", "Low" |
| Close | "close", "Close", "adj_close", "Adj Close" |
| Volume | "volume", "Volume", "vol", "Vol" |
最保險的做法是用 open, high, low, close, volume 參數明確地指定 DataFrame 中的欄位名稱, 特別是欄位名稱是中文時, 例如 df.ta.rsi(close='收盤價'). 當 df 中同時有 Adj Close 與 Close 欄位時, df.ta.rsi(close='Adj Close') 會用還原權值收盤價計算 RSI; 而 df.ta.rsi(close='Close') 則會用未還原權值收盤價計算 RSI.
透過擴展屬性 ta 呼叫指標方法 df.ta.xxx() 時, 其傳入參數還有如下表之共通參數 (所有技術指標都有) 可傳入, 主要是用來指定計算結果與 df 欄位的處理方式 :
| 共通參數 | 說明 |
|---|---|
| append | 是否將產生的技術指標欄位加入原 DataFrame(預設 False)。 |
| correction | 是否修正輸出欄位名稱中的重複名稱、特殊字元等(有些指標預設為 True)。 |
| asobject | True 時回傳 Indicator 類型物件;False(預設)時回傳 DataFrame。 |
| offset | 指標輸出向後或向前平移(shift),通常用於策略排程或對齊用途。 |
| fillna | 是否以 0 填補缺失值(NaN)。預設 False。 |
| fill_method | pandas fillna 的填補方法,例如 'ffill'、'bfill'。 |
| mamode | 若指標需使用移動平均,可指定類型(sma、ema、wma 等)。部分指標才適用。 |
| suffix | 自訂輸出欄位名稱後綴(如 RSI_14 → RSI_14_CUSTOM)。 |
| prepend | 是否在欄位前加入前綴(某些版本支援)。通常用於避免欄位衝突。 |
| _trend | 部分趨勢類指標會使用的內部參數,用於指定趨勢計算模式。 |
注意, 共通參數 append 在新版 padas-ta 中預設值已經改為 False, 呼叫 df.ta.xxx() 時必須傳入 append=True 才會將結果自動加入 DataFrame 的新增欄位裡
使用 ta.xxx() 直接呼叫技術指標函式則無共通參數, 其傳入參數為計算指標所需之 OHCLV 欄位 (Series), 以及各指標特定之參數, 例如 :
ta.rsi(df['close'], length=14)
其中第一參數 df['close'] 為計算 RSI 所需要的收盤價欄位 (Series, 必要參數); 第二參數 length 為 RSI 的特定參數 (可有可無之關鍵字參數).
一個技術指標有哪些參數可傳入可以呼叫 help() 並傳入 ta.xxx 查看, 例如 ta.rsi() :
>>> help(ta.rsi)
Help on function rsi in module pandas_ta.momentum.rsi:
rsi(close, length=None, scalar=None, talib=None, drift=None, offset=None, **kwargs)
Relative Strength Index (RSI)
The Relative Strength Index is popular momentum oscillator used to measure the
velocity as well as the magnitude of directional price movements.
Sources:
https://www.tradingview.com/wiki/Relative_Strength_Index_(RSI)
Calculation:
Default Inputs:
length=14, scalar=100, drift=1
ABS = Absolute Value
RMA = Rolling Moving Average
diff = close.diff(drift)
positive = diff if diff > 0 else 0
negative = diff if diff < 0 else 0
pos_avg = RMA(positive, length)
neg_avg = ABS(RMA(negative, length))
RSI = scalar * pos_avg / (pos_avg + neg_avg)
Args:
close (pd.Series): Series of 'close's
length (int): It's period. Default: 14
scalar (float): How much to magnify. Default: 100
talib (bool): If TA Lib is installed and talib is True, Returns the TA Lib
version. Default: True
drift (int): The difference period. Default: 1
offset (int): How many periods to offset the result. Default: 0
Kwargs:
fillna (value, optional): pd.DataFrame.fillna(value)
fill_method (value, optional): Type of fill method
Returns:
pd.Series: New feature generated.
6. 計算 RSI 指標並於 K 線圖中繪製其曲線 :
下面測試以實際從 yfinance 取得的股票資料用 pandas-ta 來計算 RSI 指標
首先匯入 yfinance 與 pandas-ta 套件 :
>>> import yfinance as yf
>>> import pandas_ta as ta
下載 yfinance 股票價量資料 :
>>> df=yf.download('0050.TW', start='2024-11-06', end='2025-01-09', auto_adjust=False)
[*********************100%***********************] 1 of 1 completed
注意, 新版 yfinance API 預設傳回已還原權值收盤價的多層欄位 DataFrame (auto_adjust 預設 True), df['Close'] 為已還原權值收盤價, 如果要同時取得已還原與未還原權值收盤價, auto_adjust 需設為 False (這樣會有 Close 與 Adj Close 兩個欄位).
由於多層欄位 DataFrame 無法直接傳給 mplfinance 繪製 K 線圖, 故用下列指令將 DataFrame 改為傳統的單層欄位 :
>>> df.columns=df.columns.map(lambda x: x[0])
顯示前 10 筆資料 :
>>> df.head()
Adj Close Close High Low Open Volume
Date
2024-11-06 47.797909 48.799999 49.512501 48.375000 48.512501 66825504
2024-11-07 48.348858 49.362499 49.512501 48.625000 48.724998 53994208
2024-11-08 48.728401 49.750000 50.000000 49.674999 49.849998 51800604
2024-11-11 48.752892 49.775002 49.775002 49.200001 49.712502 49456052
2024-11-12 47.504074 48.500000 48.962502 48.500000 48.799999 105088348
首先直接呼叫 pandas-ta 的技術指標函式 ta.rsi(), 其必要參數為收盤價, 另傳入特定參數 length 來指定週期, 傳回值為 RSI 指標值 (Series), 存入 DataFrame 新增欄位 RSI 中 :
>>> df['RSI']=ta.rsi(df['Close'], length=14)
檢視前 20 筆, 因 length=14, 故要第 15 筆紀錄才會有 RSI 值 :
>>> df.head(20)
Adj Close Close High ... Open Volume RSI
Date ...
2024-11-06 47.797909 48.799999 49.512501 ... 48.512501 66825504 NaN
2024-11-07 48.348858 49.362499 49.512501 ... 48.724998 53994208 NaN
2024-11-08 48.728401 49.750000 50.000000 ... 49.849998 51800604 NaN
2024-11-11 48.752892 49.775002 49.775002 ... 49.712502 49456052 NaN
2024-11-12 47.504074 48.500000 48.962502 ... 48.799999 105088348 NaN
2024-11-13 47.197987 48.187500 48.500000 ... 48.462502 36778360 NaN
2024-11-14 46.769474 47.750000 48.125000 ... 48.075001 48586460 NaN
2024-11-15 47.100044 48.087502 48.212502 ... 48.012501 29542324 NaN
2024-11-18 46.438900 47.412498 47.924999 ... 47.862499 53578064 NaN
2024-11-19 47.075554 48.062500 48.237499 ... 47.674999 30473284 NaN
2024-11-20 46.879662 47.862499 47.862499 ... 47.862499 312000 NaN
2024-11-21 46.365444 47.337502 47.537498 ... 47.500000 63506468 NaN
2024-11-22 47.271446 48.262501 48.299999 ... 47.775002 31862348 NaN
2024-11-25 47.100044 48.087502 48.687500 ... 48.674999 31306652 NaN
2024-11-26 46.487877 47.462502 47.575001 ... 47.525002 45563288 40.597565
2024-11-27 45.814495 46.775002 47.362499 ... 47.287498 56290744 36.769954
2024-11-28 45.741032 46.700001 46.775002 ... 46.750000 52436456 36.367131
2024-11-29 45.851223 46.812500 47.000000 ... 46.237499 32512880 37.473635
2024-12-02 46.940880 47.924999 47.924999 ... 47.125000 42176312 47.243384
2024-12-03 47.577534 48.575001 48.712502 ... 48.575001 39812424 51.965859
[20 rows x 7 columns]
接下來用 kbar 套件來繪製 K 線圖, 此套件依賴 mplfinance 來繪製 K 線圖, 但介面更簡潔, 可用 pip install kbar 安裝, 參考 :
匯入 kbar.KBar 類別, 呼叫其建構式並傳入 DataFrame 建立 KBar 物件 :
>>> from kbar import KBar
>>> kb=KBar(df)
設定字型為: Microsoft JhengHei
呼叫 KBar 物件的 addplot() 方法新增副圖繪製 RSI 曲線 (副圖要從 panel 2 起算) :
>>> kb.addplot(df['RSI'], panel=2, ylabel='RSI')
呼叫 KBar 物件的 plot() 方法繪製 K 線圖 (顯示成交量副圖與 5 日均線疊圖) :
>>> kb.plot(volume=True, mav=5)
使用指定字型: Microsoft JhengHei
字型候選清單: ['Microsoft JhengHei', 'DejaVu Sans', 'Arial']
結果如下 :
其次, 使用 df.ta.xxx() 來計算 RSI 指標, 重新下載股票資料 :
>>> df=yf.download('0050.TW', start='2024-11-06', end='2025-01-09', auto_adjust=False)
[*********************100%***********************] 1 of 1 completed
將 DataFrame 改為傳統的單層欄位 :
>>> df.columns=df.columns.map(lambda x: x[0])
顯示前 10 筆資料 (與上面一樣) :
>>> df.head()
Adj Close Close High Low Open Volume
Date
2024-11-06 47.797909 48.799999 49.512501 48.375000 48.512501 66825504
2024-11-07 48.348858 49.362499 49.512501 48.625000 48.724998 53994208
2024-11-08 48.728401 49.750000 50.000000 49.674999 49.849998 51800604
2024-11-11 48.752892 49.775002 49.775002 49.200001 49.712502 49456052
2024-11-12 47.504074 48.500000 48.962502 48.500000 48.799999 105088348
呼叫 df.ta.rsi() 方法指定以 Close 欄位計算 RSI 指標, 結果為單欄故傳回 Series :
>>> df.ta.rsi(length=14, close='Close', append=True)
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 NaN
2024-11-26 40.597565
2024-11-27 36.769954
2024-11-28 36.367131
2024-11-29 37.473635
2024-12-02 47.243384
2024-12-03 51.965859
2024-12-04 53.930191
2024-12-05 55.711091
2024-12-06 54.102319
2024-12-09 54.573219
2024-12-10 51.393309
2024-12-11 47.754493
2024-12-12 52.543689
2024-12-13 52.853987
2024-12-16 54.560375
2024-12-17 56.671434
2024-12-18 56.671434
2024-12-19 49.474000
2024-12-20 45.339886
2024-12-23 55.650059
2024-12-24 56.690637
2024-12-25 57.852403
2024-12-26 57.437595
2024-12-27 58.815685
2024-12-30 55.538436
2024-12-31 49.952179
2025-01-02 45.834974
2025-01-03 50.840252
2025-01-06 62.583698
2025-01-07 65.802355
2025-01-08 58.460939
Name: RSI_14, dtype: float64
因為 df.ta.xxx() 的共通參數 append 設為 True, 所以計算結果除了傳回來外, 還會加入 df 中 (欄名 pandas-ta 會自動決定) :
>>> df.head(20)
Close High Low Open Volume RSI_14
Date
2024-11-06 47.797909 48.495779 47.381637 47.516314 66825504 NaN
2024-11-07 48.348858 48.495779 47.626503 47.724448 53994208 NaN
2024-11-08 48.728401 48.973268 48.654941 48.826346 51800604 NaN
2024-11-11 48.752892 48.752892 48.189698 48.691675 49456052 NaN
2024-11-12 47.504074 47.957078 47.504074 47.797913 105088348 NaN
2024-11-13 47.197987 47.504070 47.136770 47.467341 36778360 NaN
2024-11-14 46.769474 47.136774 46.549096 47.087801 48586460 NaN
2024-11-15 47.100044 47.222477 46.732745 47.026584 29542324 NaN
2024-11-18 46.438900 46.940877 46.426660 46.879660 53578064 NaN
2024-11-19 47.075554 47.246960 46.573577 46.696010 30473284 NaN
2024-11-20 46.879662 46.879662 46.879662 46.879662 312000 NaN
2024-11-21 46.365444 46.561334 46.181794 46.524606 63506468 NaN
2024-11-22 47.271446 47.308175 46.793958 46.793958 31862348 NaN
2024-11-25 47.100044 47.687722 47.075556 47.675478 31306652 NaN
2024-11-26 46.487877 46.598066 46.230766 46.549093 45563288 40.597564
2024-11-27 45.814495 46.389929 45.790007 46.316468 56290744 36.769955
2024-11-28 45.741032 45.814492 45.410461 45.790004 52436456 36.367116
2024-11-29 45.851223 46.034873 45.177841 45.288030 32512880 37.473643
2024-12-02 46.940880 46.940880 46.157308 46.157308 42176312 47.243408
2024-12-03 47.577534 47.712211 47.442856 47.577534 39812424 51.965878
可見計算結果是放在新增欄位 RSI_14 中.
用 kbar 模組繪製 K 線圖 :
>>> from kbar import KBar
>>> kb=KBar(df)
設定字型為: Microsoft JhengHei
呼叫 KBar 物件的 addplot() 方法新增副圖繪製 RSI 曲線 (副圖要從 panel 2 起算),注意, 欄位名稱是 RSI_14 :
>>> kb.addplot(df['RSI_14'], panel=2, ylabel='RSI')
呼叫 KBar 物件的 plot() 方法繪製 K 線圖 (顯示成交量副圖與 5 日均線疊圖) :
>>> kb.plot(volume=True, mav=5)
使用指定字型: Microsoft JhengHei
字型候選清單: ['Microsoft JhengHei', 'DejaVu Sans', 'Arial']
結果與上面用 ta.rsi() 計算結果繪製的相同 :


沒有留言 :
張貼留言