이번에는 저번 시간에 읽은 가격 자료를 이용하여 Candle Stick 차트를 그려보도록 하겠습니다.
인터넷에서 검색해보니, 파이쏜의 그림그리는 모듈인 Matplotlib에서 Candle Stick을 그릴 수 있는 하부 모듈이 있다고 하는데, 문제는 그 모듈이 관리도 안되고 곧 없어진다 그래서 그거 안쓰고 그냥 제가 직접 그렸어요 ^^
Matplotlib에 대한 기본적인 사항은 예전에 제가 작성했던 글들 (목록은 밑에 있어요)을 참조하시기 바랍니다.
일단 코드부터 보시죠.
read_txt+plot_candle.py3.py
import sys
import numpy as np
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.ticker import AutoMinorLocator
def conv2date(mon_str,day_str,year_str):
"""
mon_str: Month Name Abbre. (3-letters)
day_str: Need to remove the last comma
year_str: 4-digit number
"""
return datetime.strptime(mon_str+day_str+year_str,'%b%d,%Y')
def draw_candlesticks(ax1,dates,prices):
### Increasing Price
pinc_idx= prices[3,:]>=prices[0,:]
pinc_prices=prices[:,pinc_idx]
pinc_dates=dates[pinc_idx]
#print(pinc_prices[0,:],pinc_prices[1,:])
pic1 = ax1.bar(pinc_dates,pinc_prices[3,:]-pinc_prices[0,:],width=width,bottom=pinc_prices[0,:],color='w',edgecolor=cc[0],linewidth=max(0.1,1/max(nt/80,0.8)))
pic1a= ax1.bar(pinc_dates,pinc_prices[1,:]-pinc_prices[3,:],width=width2,bottom=pinc_prices[3,:],color=cc[0],edgecolor=None)
pic1b= ax1.bar(pinc_dates,pinc_prices[0,:]-pinc_prices[2,:],width=width2,bottom=pinc_prices[2,:],color=cc[0],edgecolor=None)
### Decreasing Price
pdec_idx= np.logical_not(pinc_idx)
pdec_dates=dates[pdec_idx]; pdec_prices=prices[:,pdec_idx]
#print(pdec_prices[0,:],pdec_prices[1,:])
pic2 = ax1.bar(pdec_dates,pdec_prices[0,:]-pdec_prices[3,:],width=width,bottom=pdec_prices[3,:],color=cc[1],edgecolor=None)
pic2a= ax1.bar(pdec_dates,pdec_prices[1,:]-pdec_prices[0,:],width=width2,bottom=pdec_prices[0,:],color=cc[1],edgecolor=None)
pic2b= ax1.bar(pdec_dates,pdec_prices[3,:]-pdec_prices[2,:],width=width2,bottom=pdec_prices[2,:],color=cc[1],edgecolor=None)
def draw_candlesticks_misc(ax1,dates,datebuffer0=-5,datebuffer1=30):
### Decoration
ax1.xaxis_date()
myFmt = mdates.DateFormatter('%b\n%Y')
ax1.xaxis.set_major_formatter(myFmt)
ax1.set_xlim(dates[0]+timedelta(days=datebuffer0),dates[-1]+timedelta(days=datebuffer1))
ax1.set_ylim(pmin*0.8,pmax*1.1)
ax1.yaxis.set_minor_locator(AutoMinorLocator(2))
ax1.yaxis.set_ticks_position('both')
ax1.grid(which='major',axis='y',color='silver',lw=0.5,ls=':')
###--- Main ---###
## Parameters
c_name="BTC"
## Input File
in_dir='./'
in_txt_fn=in_dir+c_name+'_daily_20130428-20190715.txt'
## Read Text File
dates=[]; prices=[]
with open(in_txt_fn,'r') as f:
for i,line in enumerate(f):
if i==0:
print(line)
else:
words=line.strip().split()
if i==1:
num=len(words)
print(num,words)
elif num!=len(words):
print(num,len(words),words)
sys.exit()
dates.append(conv2date(*words[:3]))
price_tmp=[]
for ww in words[3:7]:
if "," in ww:
ww=ww.replace(",","")
price_tmp.append(float(ww))
prices.append(price_tmp)
print(dates[-1],prices[-1])
## Convert list to numpy array
prices=np.asarray(prices).T
print(prices.shape) ### Now should be [4,time_steps]
## Make time reversed (old to new)
prices=prices[:,::-1]
dates=dates[::-1]
print(prices[:,0],dates[0])
ini_date= dates[0]
tgt_dates= [datetime(2018,10,1),dates[-1]] ### Target Dates to draw chart
it= (tgt_dates[0]-ini_date).days
nt= (tgt_dates[1]-tgt_dates[0]).days+1
prices= prices[:,it:it+nt]
dates= np.array(dates[it:it+nt])
pmin,pmax= prices.min(),prices.max()
print(pmin,pmax)
###--- Plotting
##-- Page Setup --##
fig = plt.figure()
fig.set_size_inches(8.5,5) # Physical page size in inches, (lx,ly)
fig.subplots_adjust(left=0.05,right=0.95,top=0.92,bottom=0.05,hspace=0.35,wspace=0.15) ### Margins, etc.
##-- Title for the page --##
suptit="{} Price Timeseries".format(c_name)
fig.suptitle(suptit,fontsize=15) #,ha='left',x=0.,y=0.98,stretch='semi-condensed')
width=0.8; width2=width/10
cc=['g', 'darkorange']
##-- Set up an axis --##
ax1 = fig.add_subplot(1,1,1) # (# of rows, # of columns, indicater from 1)
draw_candlesticks(ax1,dates,prices)
draw_candlesticks_misc(ax1,dates)
##-- Seeing or Saving Pic --##
#- If want to see on screen -#
#plt.show()
#- If want to save to file
outdir = "./Pics/"
outfnm = outdir+"{}_price_ex1.png".format(c_name)
#fig.savefig(outfnm,dpi=100) # dpi: pixels per inch
fig.savefig(outfnm,dpi=180,bbox_inches='tight') # dpi: pixels per inch
벌써 코드가 상당히 길어졌는데요, 사실 절반 정도는 저번 시간에 다룬, 텍스트 파일에서 데이타를 읽어오는 부분입니다. 이번에 추가된 부분은,
이렇게 되어있습니다. 별로 어렵지 않죠? ^^
몇 가지 설명
일단은 이정도면 되려나요.
제가 너무 익숙해서 지나가버렸지만, 초보자에겐 어려운 부분이 있을거에요. 댓글로 질문 주시길!
다음 시간에는 이동 평균 Moving Average를 계산해서 그림에 추가하도록 하겠습니다.
관련 글들
Matplotlib List
[Matplotlib] 00. Intro + 01. Page Setup
[Matplotlib] 02. Axes Setup: Subplots
[Matplotlib] 03. Axes Setup: Text, Label, and Annotation
[Matplotlib] 04. Axes Setup: Ticks and Tick Labels
[Matplotlib] 05. Plot Accessories: Grid and Supporting Lines
[Matplotlib] 06. Plot Accessories: Legend
[Matplotlib] 07. Plot Main: Plot
[Matplotlib] 08. Plot Main: Imshow
[Matplotlib] 09. Plot Accessary: Color Map (part1)
[Matplotlib] 10. Plot Accessary: Color Map (part2) + Color Bar
F2PY List
[F2PY] 01. Basic Example: Simple Gaussian 2D Filter
[F2PY] 02. Basic Example: Moving Average
[F2PY] 03. Advanced Example: Using OpenMP
Scipy+Numpy List
[SciPy] 1. Linear Regression (Application to Scatter Plot)
[SciPy] 2. Density Estimation (Application to Scatter Plot)
[Scipy+Numpy] 3. 2D Histogram + [Matplotlib] 11. Plot Main: Pcolormesh
Road to Finance
#00 Read Text File
#01 Draw CandleSticks