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

結果如下 : 



沒有留言 :