엑셀_파이썬_기타 코딩

파이썬으로 3D 일드 커브(yield curve) 그리기

2023. 6. 14. 17:16

예전에 해봤던 입체 일드커브 그래프 작업을 올려본다. matplotlib 라이브러리나 plotly를 써서 어렵지 않게 그릴 수 있다. 억지로 작동만 하게 짰을 뿐 코드는 상당히 더럽다.

일드커브를 3d로 그리는 건 재미는 있지만 실용적으로는 크게 의미가 없다. 내 생각에는 3차원 이상의 데이터는 사람이 일반적으로 하는 논리적인 사고 방식에 부합하지 않는다. 

구글 코랩으로 돌렸고 raw데이터로 국채 금리 엑셀 데이터를 드라이브에 집어넣어 끌어서 사용했다. 

from google.colab import drive
drive.mount('/content/drive')

# https://github.com/blaiklock/3d_yield_curve/blob/master/3d_yield_curve.ipynb

import numpy as np
import pandas as pd
import os
import mpl_toolkits.mplot3d 
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as dates
import matplotlib.ticker as ticker
from mpl_toolkits.mplot3d import Axes3D as ax

excel_direc1 = str('/content/drive/MyDrive/Colab Notebooks/')
excel_direc2= str('yieldcurveplot.xlsx')
excel_direc = os.path.join(excel_direc1, excel_direc2)
print(excel_direc)
print(os.path.exists(excel_direc))

df_kor_yield = pd.read_excel(excel_direc, header =0, engine= 'openpyxl') 
df_kor_yield.set_index('date', drop= True, inplace =True )
df_kor_yield.sort_index(ascending = True, inplace= True ) 
print(df_kor_yield)

# date = [ float(i) for i in df_kor_yield.index.tolist()] 
# mat= [float(i) for i in df_kor_yield.columns.tolist()]

date= df_kor_yield.index
mat=df_kor_yield.columns
print(date)
print(mat)

x, y = np.meshgrid(np.arange(len(mat)),np.arange(len(date)))

z= np.array([[df_kor_yield [x][y] for x in mat] for y in date ])
z_list = z.tolist()
z_contour =  np.array([[df_kor_yield [x][y]+0.01 for x in mat] for y in date ])
print(z_contour)

# print(MAT)
# print(DATE)
# print(yield_value_np)

# print(DATE.shape)
# print(MAT.shape)
# print(yield_value_np.shape)
# print(DATE[1].dtype)
# print(MAT[1].dtype)
# print(yield_value_np[1].dtype)

시간축이 제대로 표시안되고 있다. 여유가 생기면 추가해봐야 할 부분이다.

import matplotlib.tri as mtri

fontlabel = {"fontsize":"large", "color":"black", "fontweight":"normal"}

fig, axs = plt.subplots(2, 2, sharex=False, figsize = (20,15), subplot_kw={"projection":"3d"} )
axs[0][0].plot_surface(y,x,z, cmap='GnBu',antialiased=False )
axs[0][0].set_xlabel("date",fontdict=fontlabel, labelpad=16)
axs[0][0].set_ylabel("maturity",fontdict=fontlabel, labelpad=16)
axs[0][0].set_zlabel("ytm",fontdict=fontlabel, labelpad=16)

# axs[0][1].plot_trisurf(mat, date, z_list, cmap="GnBu")
axs[0][1].contour(y, x, z_contour, levels=20, colors="k",alpha=0.6, linewidths=0.7)
axs[0][1].plot_surface(y,x,z, cmap='viridis',antialiased=False,alpha=0.95 )
axs[0][1].view_init(elev=30., azim= 240 )
axs[0][1].set_xlabel("date",fontdict=fontlabel, labelpad=16)
axs[0][1].set_ylabel("maturity",fontdict=fontlabel, labelpad=16)
axs[0][1].set_zlabel("ytm",fontdict=fontlabel, labelpad=16)

axs[1][0].plot_surface(y,x,z, cmap='GnBu',antialiased=False )
axs[1][0].view_init(elev=0., azim= 270 )

axs[1][1].plot_surface(y,x,z, cmap='GnBu',antialiased=False )
axs[1][1].view_init(elev=0., azim= 0 )


*Plotly로 그리면 조작가능한 3d그래프를 만들 수 있다. 개인 재량으로 설정할 수 있는 옵션은 좀 더 적은듯 하다. 

# https://plotly.com/python/3d-surface-plots/

import plotly.graph_objects as go

import pandas as pd

z_data = pd.read_excel ('/content/drive/MyDrive/Colab Notebooks/yieldcurveplot.xlsx',  header =0, engine= 'openpyxl')
z_data.set_index('date', drop= True, inplace =True )
z_data.sort_index(ascending = False, inplace= True ) 
print(z_data)

fig = go.Figure(data=[go.Surface(x=z_data.columns, y= z_data.index, z=z_data.values, colorscale = 'pubu')])

          # colorscale:  ['aggrnyl', 'agsunset', 'algae', 'amp', 'armyrose', 'balance',
          #    'blackbody', 'bluered', 'blues', 'blugrn', 'bluyl', 'brbg',
          #    'brwnyl', 'bugn', 'bupu', 'burg', 'burgyl', 'cividis', 'curl',
          #    'darkmint', 'deep', 'delta', 'dense', 'earth', 'edge', 'electric',
          #    'emrld', 'fall', 'geyser', 'gnbu', 'gray', 'greens', 'greys',
          #    'haline', 'hot', 'hsv', 'ice', 'icefire', 'inferno', 'jet',
          #    'magenta', 'magma', 'matter', 'mint', 'mrybm', 'mygbm', 'oranges',
          #    'orrd', 'oryel', 'oxy', 'peach', 'phase', 'picnic', 'pinkyl',
          #    'piyg', 'plasma', 'plotly3', 'portland', 'prgn', 'pubu', 'pubugn',
          #    'puor', 'purd', 'purp', 'purples', 'purpor', 'rainbow', 'rdbu',
          #    'rdgy', 'rdpu', 'rdylbu', 'rdylgn', 'redor', 'reds', 'solar',
          #    'spectral', 'speed', 'sunset', 'sunsetdark', 'teal', 'tealgrn',
          #    'tealrose', 'tempo', 'temps', 'thermal', 'tropic', 'turbid',
          #    'turbo', 'twilight', 'viridis', 'ylgn', 'ylgnbu', 'ylorbr',
          #    'ylorrd'].

fig.update_layout(title='KTB yield curve', autosize=False,
                  width=1000, height=500,
                  margin=dict(l=0, r=50, b=0, t=90))
fig.update_traces(contours_z=dict(show=True, usecolormap=True,
                                  highlightcolor="limegreen", project_z=True))
fig.update_layout(scene_aspectmode='manual',
                  scene_aspectratio=dict(x=1, y=3, z=1)
                  )
fig.update_layout(scene = dict(
                    xaxis = dict(
                        ticktext= ['2Y','3Y','4Y','5Y','7Y','10Y'],
                        tickvals= [0,1,2,3,4,5]),
                    # yaxis = dict(
                    #     nticks=5, tickfont=dict(
                    #         size=12,
                    #         family='Old Standard TT, serif',),
                    #     ),
                    # zaxis = dict(
                    #     nticks=4, ticks='outside',
                    #     tick0=0, tickwidth=4),
                    ),
                    width=700,
                    margin=dict(r=10, l=10, b=10, t=10)
                  )
fig.update_layout(scene = dict(
                    xaxis_title='Tenor',
                    yaxis_title='date',
                    zaxis_title='yield'),
                    width=700,
                    margin=dict(r=20, b=10, l=10, t=10))
fig.show()

지금은 사진만 다운받았지만, 코드를 돌리면 3d로 움직일 수 있다.


이하는 레퍼런스 링크다.