宽客秀

宽客秀

Quant.Show的Web3站点,Archives from quant.show

基於matplotlib的動態複盤

本文基於 matplotlib,動態復盤了滬深 300ETF 和納指 ETF 的近 60 天來的走勢。通過對動態復盤的製作,對 matplotlib 中常用的函數進行總結和整理。事實上,動態復盤不是目的,其業務意義也不是很大。基於此的 matplotlib 的筆記整理才是本文最大的初衷。

1. 相關庫導入#

# 導入所需庫
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

確定 matplotlib 的版本(筆者本次使用的 3.0.2)#

print(mpl.__version__)

2. 全局參數初始化#

matplotlib 主要通過 plt.rc、plt.rcParams 來進行全局參數的設定。以下兩種設定方法是等價的。

plt.rc('axes', axisbelow=True)

plt.rcParams['axes.axisbelow'] = True

除此以外,還可以通過 plt.rcParams.update () 來實現,該方法更為便捷。

# 設置全局參數
#font.sans-serif:用來正常顯示中文標籤
#animation.emded_limit:動態圖太大了,很容易突破默認 byte,
#如果不設置,顯示出來的圖是不完整的,
#保險起見可以設一個比較大的數,比如 2^64。
params = {'axes.axisbelow': True,
'font.sans-serif': 'SimHei',
'figure.figsize': (16, 8),
'animation.embed_limit':2**64}
plt.rcParams.update(params)

設置顯示風格#

plt.style.use('ggplot')

在使用的過程中,也可以隨時調節參數,進行個性化定制。此時,只需要回滾為初始值即可。

plt.rcParams.update(mpl.rcParamsDefault)

3. 數據導入 — 基於 JoinQuant#

security_list=['510300.XSHG','513100.XSHG']

滬深 300ETF#

stock = '510300.XSHG'

納指 ETF#

stock2 = '513100.XSHG'
df = history(count=60, unit='1d', field='close', security_list=security_list, df=True, skip_paused=False, fq='pre')

4. 靜態價格圖#

當第一次執行 plt.xxx () 畫圖代碼時,系統會去判斷是否已經有了 figure 對象,
如果沒有,系統會自動創建一個 figure 對象,並且在這個 figure 之上,自動創建一個 axes 坐標系 (注意:默認創建一個 figure 對象,一個 axes 坐標系)。也就是說,如果我們不設置 figure 對象,那麼一個 figure 對象上,只能有一個 axes 坐標系,即我們只能繪製一個圖形。Figure、Axes 及 Axis 的關係可以參考圖 1 所示。


圖 1 Figure、Axes 及 Axis 的關係

Figure、Axes 及 Axis 的關係


以 plt.plot (x,y,format) 為例,plt.plot () 默認畫折線圖,參數 format 由 {color}{marker}{linestyle} 三方面的要素組成(該三方面的要素亦可單獨指定),比如,

  • ‘go-’:綠色點與實線
  • 'r*--' : 紅色星星與虛線
  • 'bD-.' : 藍色菱形與點劃線

plt.text 和 plt.annotate 可以用來追加文字及註釋。

plt.plot(df.index,df[stock],'r*--')

用 Arrow Props 和 bbox 進行註釋#

需要被註釋的點的位置設定#

x_annotate = df[stock].idxmax(axis=1)
y_annotate = max(df[stock])

xy: 需要被註釋的點的位置#

xytext:註釋文本的位置#

arrowprops: xy→xytext 的箭頭#

bbox:註釋文本顯示形狀#

plt.annotate(y_annotate,
xy=(x_annotate, y_annotate), xytext=(x_annotate, y_annotate*1.02),
bbox=dict(boxstyle='square', fc='red', linewidth=0.2),
arrowprops=dict(facecolor='red', shrink=0.01, width=0.1),
fontsize=12, color='white', horizontalalignment='center')

文字標註#

文字標註位置設定#

x_text = df[stock].idxmin(axis=1)
y_text = min(df[stock])

文字標註#

plt.text (df.index [-1], df [stock][-1],s="滬深 300 ETF", color='red', size=12, ha='center', va='top')


圖 2 靜態價格圖

bcd6a9c51dd71692459d3979143dfb13


一個 Figure 上可以設定佈置一個 Axes,主要通過 plt.subplot 的方式實現。如果要實現更為複雜的子圖佈局,可以使用 plt.subplot2grid、plt.GridSpec 函數。這裡就不一一展開。

# 獲取每個位置的 axes 對象

subplot (x,y,n) 表示 axes 子圖排列為 x 行 * y 列,n 為第 n 個子圖#

axes1 = plt.subplot(211)
axes1.plot(df.index,df[stock])

axes2 = plt.subplot(212)
axes2.plot(df.index, df[stock2])

5. 動態價格復現#

(1)構造靜態畫圖函數#

構造一個 animate (frame),其中 frame 可看成是 df 的變化的 index。不同的 frame,就會切片得到 df.iloc [,:]。

#構造一個 animate (frame),其中 frame 可看成是 df 的變化的 index。
#不同的 frame,就會切片得到 df.iloc [,:]
def animate(frame):
axes1.clear()
axes2.clear()
# 不同的 frame,就會切片得到 df.iloc [,:]
df_temp = df.iloc[0,:]
# 折線圖
axes1.plot(df_temp.index,df_temp[stock],color='blue')
axes2.plot(df_temp.index,df_temp[stock2],'r*--')
#
axes1.set_xlabel (' 日期 ')
axes1.set_ylabel (' 滬深 300 ETF', color='blue')
axes1.tick_params(axis='y', rotation=0, labelcolor='blue' )

axes2.set\_ylabel("納指ETF", color='red')
axes2.tick\_params(axis='y', labelcolor='red')
axes2.set\_title("滬深300ETF & 納指ETF 近3個月表現", fontsize=18)

# 文字標識    
axes1.text(df\_temp.index\[-1\], df\_temp\[stock\]\[-1\],s='滬深300 ETF', color='blue', size=7, ha='center', va='top')
axes2.text(df\_temp.index\[-1\], df\_temp\[stock2\]\[-1\],s='納指ETF', color='red', size=7, ha='center', va='top')

# 註釋with Arrow Props and bbox
x\_annotate\_min = df\_temp\[stock\].idxmin(axis=1)
y\_annotate\_min = min(df\_temp\[stock\])
# xy:需要註釋的點的位置
# xytext:註釋的位置
# arrowprops: xy→xytext的箭頭
axes1.annotate(y\_annotate\_min, 
             xy=(x\_annotate\_min, y\_annotate\_min), 
             xytext=(x\_annotate\_min, y\_annotate\_min\*0.98),
             bbox=dict(boxstyle='square', fc='blue', linewidth=0.1),
             arrowprops=dict(facecolor='blue', shrink=0.01, width=0.1), 
             fontsize=12, color='white', horizontalalignment='center')

x\_annotate\_max = df\_temp\[stock\].idxmax(axis=1)
y\_annotate\_max = max(df\_temp\[stock\])

axes1.annotate(y\_annotate\_max, 
          xy=(x\_annotate\_max, y\_annotate\_max), 
          xytext=(x\_annotate\_max, y\_annotate\_max\*1.01),
         bbox=dict(boxstyle='square', fc='blue', linewidth=0.1),
         arrowprops=dict(facecolor='blue', shrink=0.01, width=0.1), 
         fontsize=12, color='white', horizontalalignment='center')

x\_annotate2\_min = df\_temp\[stock2\].idxmin(axis=1)
y\_annotate2\_min = min(df\_temp\[stock2\])
# xy:需要註釋的點的位置
# xytext:註釋的位置
# arrowprops: xy→xytext的箭頭
axes2.annotate(y\_annotate2\_min, 
             xy=(x\_annotate2\_min, y\_annotate2\_min), 
             xytext=(x\_annotate2\_min, y\_annotate2\_min\*0.98),
             bbox=dict(boxstyle='square', fc='red', linewidth=0.1),
             arrowprops=dict(facecolor='red', shrink=0.01, width=0.1), 
             fontsize=12, color='white', horizontalalignment='center')

# Annotate with Arrow Props and bbox
x\_annotate2\_max = df\_temp\[stock2\].idxmax(axis=1)
y\_annotate2\_max = max(df\_temp\[stock2\])

# xy:需要註釋的點的位置
# xytext:註釋的位置
# arrowprops: xy→xytext的箭頭
axes2.annotate(y\_annotate2\_max, 
             xy=(x\_annotate2\_max, y\_annotate2\_max), 
             xytext=(x\_annotate2\_max, y\_annotate2\_max\*1.01),
             bbox=dict(boxstyle='square', fc='red', linewidth=0.1),
             arrowprops=dict(facecolor='red', shrink=0.01, width=0.1), 
             fontsize=12, color='black', horizontalalignment='center')
(2)生成 figure、axes1、axes2#

和靜態價格圖的生成不同,這裡我們顯示調用 figure 函數。可以通過 axes.twinx 來實現右邊的 y 軸。

fig, axes1 = plt.subplots(1, 1, dpi=80)

生成右側的 y 軸#

axes2 = axes1.twinx()

(3)調用 FuncAnimation () 函數#

#參數設定
#fig:即 Figure 對象
#animate:之前定義的靜態畫圖函數
#frames:動畫的幀數。通過該幀數來設定 animate 的頻率。
#interval:每一幀的時間間隔
ani = FuncAnimation(fig,
animate,
frames=np.arange(1,df.shape[0],1),
interval=300)
ani.save("movie.mp4")

參考文獻並推薦閱讀:

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。