Python 用來繪製 K 線圖的主要套件是 mplfinance, 它可根據傳入的 OHLCV 價量資料 DataFrame 繪製 K 線, 並提供了豐富的函式可繪製疊圖與副圖, 搭配 Ta-Lib 套件則可在副圖中繪製各種技術指標, 我也寫了一個 kbar.py 模組來簡化畫 K 線圖時的參數設定, 參考 :
但若要同時可在命令列以及 Gradio 與 Streamlit 的 web app 中利用此 kbar.py 繪製 K 線圖的話, 必須改寫之前的 kbar.py, 因為 mplfinance 的 plot() 函式預設傳回 None, 這在命令列執行沒有問題, 但若要在 Gradio 與 Streamlit 的 web app 中使用 mplfinance 畫 K 線圖, 則必須傳入 returnfig=True 參數, 這樣 plot() 函式就會傳回 (fig, axes) 元組, 只要將畫布物件 fig 傳給 Gradio 的 Plot() 函式或 Streamlit 的 pyplot() 函式即可. 修改後的 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 embedding:
fig, axes=mpf.plot(self.df, returnfig=True, **kwargs)
return fig
else:
mpf.plot(self.df, **kwargs)
主要是在 KBar 類別的 plot() 方法中添加 embedding 參數, 預設值為 False, 因此在命令列呼叫 plot() 方法時不必傳入 embedding 參數; 但在 Gradio 或 Streamlit app 中則要傳入 embedding=True.
以下測試使用 yfinance 套件取得台股的 OHLCV 價量資料, 用法參考 :
1. 在 Gradio app 中繪製 K 線圖 :
Gradio 是 HuggingFace 所維護的開放原始碼 web app 套件, 關於 Gradio 用法參考 :
以下是在 Gradio 中使用 mplfinance 畫 K 線圖範例 :
# gradio_kbar_1.py
import gradio as gr
import kbar # 匯入 kbar
import yfinance as yf # 匯入 Yahoo Finance
from talib.abstract import RSI, MFI # 匯入 Ta-Lib 的技術指標類別
def plot_kbar():
df=yf.download('0050.tw', start='2024-07-01', end='2024-08-21') # 取得價量資料
df.columns=[column.lower() for column in df.columns] # Ta-Lib 要求欄位名稱為全小寫
kb=kbar.KBar(df) # 建立 KBar 物件
rsi=RSI(df) # 建立 RSI 指標物件
mfi=MFI(df, timeperiod=14) # 建立 MFI 指標物件
if not rsi.isna().all(): # 確保 RSI 有值
kb.addplot(rsi, panel=2, ylabel='RSI')
if not mfi.isna().all(): # 確保 MFI 有值
kb.addplot(mfi, panel=3, ylabel='MFI')
# 繪製 K 線圖與技術指標副圖
fig=kb.plot(volume=True, mav=[3, 5, 7], embedding=True, title='台灣五十')
return fig # 傳回 Figure 物件
iface=gr.Interface(
fn=plot_kbar, # 繪製函數
inputs=[], # 無需用戶輸入
outputs=gr.Plot(), # 輸出為 Gradio 的 Plot 物件
title='Gradio Candle Chart',
flagging_mode='never',
)
iface.launch()
此例在呼叫 KBar 物件的 plot() 方法時傳入 embedding=True 參數, 這樣就會傳回畫布物件 fig, 將其傳回給 Gradio.Plot() 即可在 Gradio app 中顯示 mplfinance 繪製的圖形, 結果如下 :
2. 在 Streamlit app 中繪製 K 線圖 :
Streamlit 是一個輕量好用的 Python web app 套件, 廣泛應用在機器學習, 資料科學, 與人工智慧專案的展示應用上. 下面是在 Streamlit app 中用 mplfinance 繪製 K 線圖範例 :
# streamlit_kbar_1.py
import streamlit as st
import kbar # 匯入 kbar
import yfinance as yf # 匯入 Yahoo Finance
from talib.abstract import RSI, MFI # 匯入 Ta-Lib 的技術指標類別
df=yf.download('0050.tw', start='2024-07-01', end='2024-08-21') # 取得價量資料
df.columns=[column.lower() for column in df.columns] # Ta-Lib 要求欄位名稱為全小寫
kb=kbar.KBar(df) # 建立 KBar 物件
rsi=RSI(df) # 建立 RSI 指標物件
mfi=MFI(df, timeperiod=14) # 建立 MFI 指標物件
if not rsi.isna().all(): # 確保 RSI 有值
kb.addplot(rsi, panel=2, ylabel='RSI')
if not mfi.isna().all(): # 確保 MFI 有值
kb.addplot(mfi, panel=3, ylabel='MFI')
# 繪製顯示成交量與 3, 5, 7 日均線之 K 線圖
fig=kb.plot(volume=True, mav=[3, 5, 7], embedding=True)
st.title("Streamlit Candle Chart")
st.pyplot(fig)
此例在呼叫 KBar 物件的 plot() 方法時傳入 embedding=True 參數, 這樣就會傳回畫布物件 fig, 將其傳給 Streamlit 的 pyplot() 函式即可在 Streamlit app 中顯示 mplfinance 繪製的圖形, 結果如下 :
2025-01-21 補充 :
今天測試 kbar.py 時發現一個 Bug : 如果在呼叫 plot() 方法時傳入 returnfig 參數會出現 duplicate rturnfig 錯誤, 原因在於傳入 plot() 的 returnfig 會出現在 **kwargs 的字典鍵中, 而 kbar.py 的下列程式碼又傳入 returnfig=True 變成有兩個 returnfig 鍵導致錯誤發生 :
if embedding:
fig, ax=mpf.plot(self.df, returnfig=True, **kwargs)
原來的 kbar.py 因為此嵌入用途新增了一個 embedding 參數實屬多此一舉, 應該回歸只使用原生地 returnfig 參數來控制要不要傳回 Figure 物件才對, 茲將 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, **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)
此處先判斷 kwargs 裡面有無 returnfig 參數傳入, 有的話且為 True 表示圖需內嵌故傳回 Figure 物件, 否則就不傳回 Figure 物件, 經測試不管在內嵌或一般使用情境皆可正常繪製圖形. 改用此新版 kbar.py 後, 上面範例程式中的 embedding=True 都要配合改成 returnfig=True.
2025-01-23 補充 :
今天在進行 kbar.py 打包上傳 PyPi 的準備時重新審視其功能完善性, 發覺在傳入 returnfig=True 時只傳回 Figure 畫布物件似乎不夠完備, 應該連同繪圖區 (軸) 物件串列 Axes 也一起傳回去才對, 這樣在需要進一步自訂繪圖 (例如在主圖上畫一條額外的水平線) 時才有辦法利用 Axes 物件進行加工, 所以進一步修改 kbars.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, **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)
這樣上面的 Gradio 範例程式碼要修改為 :
# gradio_kbar_2.py
import gradio as gr
import kbar # 匯入 kbar
import yfinance as yf # 匯入 Yahoo Finance
from talib.abstract import RSI, MFI # 匯入 Ta-Lib 的技術指標類別
def plot_kbar():
df=yf.download('0050.tw', start='2024-07-01', end='2024-08-21') # 取得價量資料
df.columns=[column.lower() for column in df.columns] # Ta-Lib 要求欄位名稱為全小寫
kb=kbar.KBar(df) # 建立 KBar 物件
rsi=RSI(df) # 建立 RSI 指標物件
mfi=MFI(df, timeperiod=14) # 建立 MFI 指標物件
if not rsi.isna().all(): # 確保 RSI 有值
kb.addplot(rsi, panel=2, ylabel='RSI')
if not mfi.isna().all(): # 確保 MFI 有值
kb.addplot(mfi, panel=3, ylabel='MFI')
# 繪製 K 線圖與技術指標副圖
fig, axes=kb.plot(volume=True, mav=[3, 5, 7], returnfig=True, title='台灣五十')
return fig # 傳回 Figure 物件
iface=gr.Interface(
fn=plot_kbar, # 繪製函數
inputs=[], # 無需用戶輸入
outputs=gr.Plot(), # 輸出為 Gradio 的 Plot 物件
title='Gradio Candle Chart',
flagging_mode='never',
)
iface.launch()
而 Streamlit 的範例程式碼也要修改為 :
# streamlit_kbar_2.py
import streamlit as st
import kbar # 匯入 kbar
import yfinance as yf # 匯入 Yahoo Finance
from talib.abstract import RSI, MFI # 匯入 Ta-Lib 的技術指標類別
df=yf.download('0050.tw', start='2024-07-01', end='2024-08-21') # 取得價量資料
df.columns=[column.lower() for column in df.columns] # Ta-Lib 要求欄位名稱為全小寫
kb=kbar.KBar(df) # 建立 KBar 物件
rsi=RSI(df) # 建立 RSI 指標物件
mfi=MFI(df, timeperiod=14) # 建立 MFI 指標物件
if not rsi.isna().all(): # 確保 RSI 有值
kb.addplot(rsi, panel=2, ylabel='RSI')
if not mfi.isna().all(): # 確保 MFI 有值
kb.addplot(mfi, panel=3, ylabel='MFI')
# 繪製顯示成交量與 3, 5, 7 日均線之 K 線圖
fig, axes=kb.plot(volume=True, mav=[3, 5, 7], returnfig=True)
st.title("Streamlit Candle Chart")
st.pyplot(fig)
這兩個範例使用新的 kbar.py 測試 OK.
沒有留言 :
張貼留言