[Python] Road to Finance #03 CSV 파일 읽어서 놀아보기

in sct •  5 years ago  (edited)

오늘의 예제: CSV 파일 읽어서 데이타 불러들이기

전에 언급했듯이 이번 시리즈를 위해 @roostermine 님께서 http://www.cryptodatadownload.com/data/northamerican/ 라고 하는 훌륭한 사이트를 알아봐주셨습니다. 이 사이트에 가보면 여러 거래소의 거래 기록이 모아져 있습니다. 저는 이곳에서 북미의 모든 거래소의 BTCUSD 기록을, Daily와 1-hourly 모두 다 다운받았습니다. 파이쏜 프로그램으로 웹에 있는 링크에서 파일을 직접 다운받을 수도 있을 것 같은데, 그 부분은 본 시리즈의 범위를 넘어서므로 (지금은 제가 그거 어떻게 하는 지 몰라서) 넘어가도록 하겠습니다.

이 사이트에서 제공되는 파일의 형태가 바로 Comma Separated Values 즉 CSV 파일입니다. 이름이 거창하긴 한데, 사실 별 거 없습니다. 텍스트 파일인데, 자료의 값들 사이가 오직 Comma (",") 로만 이뤄어 졌다는 뜻입니다. 그래서 지난 글 #00을 조금만 수정하면 됩니다.

더하여, 이제 데이타가 많아졌으므로, 데이타는 "Data"라고 하는 서브 폴더에 저장하도록 하겠습니다.

아래는 위 사이트에서 다운받은 CSV 파일을 읽어들이는 부분을 함수로 만든 것입니다.

import sys
import numpy as np
from datetime import datetime, timedelta

def conv2date(dateinfo):
    """
    Date Format: YYYY-MM-DD HH-AM (or PM)
    """
    return datetime.strptime(dateinfo,'%Y-%m-%d %I-%p')

def load_csv_data(fname):
    """
    Input: file name with directory information

    Assume that we already know the structure of csv file

    Output: Time info, Prices, and Volumes: All togerther in a dictionary
    """

    print(fname.split('/')[-1])
    dates=[]; prices=[]; volumes=[]
    ## Read Text CSV File
    with open(fname,'r') as f:
        for i,line in enumerate(f):
            if i==0:
                print(line)
            elif i==1:
                headers=line.strip().split(',')
                num=len(headers)
                print(num,headers)
            else:
                words=line.strip().split(',')
                if num!=len(words):
                    print(num,len(words),words)
                    sys.exit("Data entry is incomplete.")

                dates.append(conv2date(words[0]))
                prices.append(list(map(float,words[2:6])))
                volumes.append([float(x) for x in words[6:]])

        dates=np.asarray(dates)[::-1]
        prices=np.asarray(prices)[::-1,:]
        volumes=np.asarray(volumes)[::-1,:]
        print(dates.shape,prices.shape,volumes.shape)
        print( "Done to read a CSV file!")
        
        return {'date':dates, 'prices':prices, 'volumes':volumes}

몇 가지 설명

  1. "conv2date"라는 함수는 예전과 거의 같습니다. 시간/날짜 정보의 형태만 살짝 바뀌었습니다.
  2. "load_csv_data"라는 함수는 필요로 하는 것이 디렉토리 정보가 포함된 파일 이름밖에 없습니다. 즉, 모든 파일이 동일한 형태임을 가정하고 있고, 또 그 형태를 미리 알고 있다는 뜻입니다. 아무 CSV 파일을 다 이걸로 읽을 수 있는 건 아닙니다.
  3. 기본 구조는, 각 줄에서 날짜정보/가격정보/거래량 정보 각각을 List에 차곡차곡 쌓은 후 나중에 Numpy Array로 변환하고, 마지막에는 Dictionary 형태로 모두 합쳐서 값을 돌려줍니다.
  4. Dictionary의 장점은 "이름"으로 데이타에 접근할 수 있어서 직관적이라는 점이고, 단점은 그만큼 복잡해진다는 점입니다.
  5. 데이타 원본이 현재에서 과거 순이므로, 뒤집어서 과거에서 현재로 바꿔줬습니다.
  6. 텍스트 파일에서 읽어들인 숫자들은 문자열 형태이므로 숫자 형태(여기서는 float)로 바꿔줘야 합니다. 위에는 같은 내용을 2가지 방법으로 표현해 봤습니다. (내장 함수 map을 이용하는 방법 vs. in-line for를 이용하는 방법)

그리고 위 함수를 포함해서 프로그램은 아래와 같습니다. (read_csv_data.py3.py)

###--- Main ---###

## Input File
in_dir='./Data/'
in_csv_fn=in_dir+'Bitfinex_BTCUSD_1h.csv'

data=load_csv_data(in_csv_fn)

print(data['date'][0],data['prices'][0],data['volumes'][0])
print(data['date'][-1],data['prices'][-1],data['volumes'][-1])



위 프로그램을 실행하면 다음과 같이 나옵니다.

>> python3 read_csv_data.py3.py
Bitfinex_BTCUSD_1h.csv
Timestamps are UTC timezone,https://www.CryptoDataDownload.com

8 ['Date', 'Symbol', 'Open', 'High', 'Low', 'Close', 'Volume BTC', 'Volume USD']
(15521,) (15521, 4) (15521, 2)
Done to read a CSV file!
2017-10-09 09:00:00 [ 4575.4  4589.5  4568.6  4585.7] [  6.28890000e+02   2.87889786e+06]
2019-07-18 01:00:00 [ 9617.5  9813.1  9560.3  9748.7] [  5.45670000e+02   5.28719882e+06]


자료를 읽어들였으니 여기에 #01에서 다뤘던 캔들스틱 그래프 부분을 붙여볼 수도 있겠는데, 여기선 이 자료로 조금 더 놀아보도록 하겠습니다.

위의 2개의 함수 부분은 공통이구요, 아래 실행시키는 부분을 약간 변형했습니다. 여기서는 Bitfinex와 Coinbase 이렇게 거래소 2군데의 자료를 불러와 서로 비교해보도록 하겠습니다.

"read_csv_data+simple_plot.py3.py"

###--- Main ---###

## Parameters
c_name="BTCUSD"
Exchanges=['Bitfinex','Coinbase']

## Input File
in_dir='./Data/'

data=[]
for ex_name in Exchanges:
    in_csv_fn=in_dir+'{}_{}_1h.csv'.format(ex_name,c_name)
    data.append(load_csv_data(in_csv_fn))

    print(ex_name)
    print(data[-1]['date'][0],data[-1]['prices'][0],data[-1]['volumes'][0])
    print(data[-1]['date'][-1],data[-1]['prices'][-1],data[-1]['volumes'][-1])
    print('\n')

### Check consistency between data
if data[0]['date'][-1] != data[1]['date'][-1]:
    print('Time stamp is inconsistent',data[0]['date'][-1],data[1]['date'][-1])
    sys.exit()

### Cut for last 10 days
xdate= data[0]['date'][-240:]
## Coinbase price - Bitfinex price
yprice_delta= data[1]['prices'][-240:,:]-data[0]['prices'][-240:,:]

###--- Plotting
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.ticker import AutoMinorLocator

##-- 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 Difference [{} - {}]".format(c_name,Exchanges[1],Exchanges[0])
fig.suptitle(suptit,fontsize=15)  #,ha='left',x=0.,y=0.98,stretch='semi-condensed')

cc=['r','g','b','y']
lname=['Open','High','Low','Close']

##-- Set up an axis --##
ax1 = fig.add_subplot(1,1,1)   # (# of rows, # of columns, indicater from 1)
for i in range(4):
    ax1.plot(xdate,yprice_delta[:,i],color=cc[i],lw=0.7,ls='-',label=lname[i])

    print("{}: Mean={:.2f}, RMSD={:.3f}".format(lname[i],yprice_delta[:,i].mean(),np.sqrt(np.power(yprice_delta[:,i],2).mean())))
    
ax1.axhline(y=0.,color='0.5',lw=0.5,ls='--')
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%m-%d\n%Y'))
    
ax1.legend(loc='lower right',bbox_to_anchor=(0.97, 0.05),fontsize=11,ncol=2)  # x and y relative location in ax1


##-- Seeing or Saving Pic --##

#- If want to see on screen -#
#plt.show()

#- If want to save to file
outdir = "./Pics/"
outfnm = outdir+"{}_price_diff.{}vs{}.png".format(c_name,Exchanges[1],Exchanges[0])
#fig.savefig(outfnm,dpi=100)   # dpi: pixels per inch
fig.savefig(outfnm,dpi=180,bbox_inches='tight')   # dpi: pixels per inch



몇 가지 설명

  1. 거래소 이름을 미리 적어놓고, 그 거래소 이름에 맞는 데이타 CSV 파일을 불러오고 있습니다. 이렇게 하면 나중에 여러 거래소의 자료를 불러올 때 편리하겠죠. 물론 CSV 파일의 이름 형식이 동일하기에 가능한 방법입니다.
  2. 여기서 "data"라는 변수는 List로 안에 Dictionary 2개가 들어있습니다. 각각의 Dictionary는 3가지의 데이타가 들어있고, 각각의 데이타는 Numpy Array입니다.
  3. 편의를 위해 최근 10일만 잘라서 썼습니다. Coinbase 가격에서 Bitfinex 가격을 빼서 그 차이를 보는 게 목적입니다.
  4. 중간에 평균과 RMSD를 화면에 출력해봤습니다. RMSD는 Root-Mean-Squared-Difference의 약자입니다.

이 프로그램을 실행하면 다음과 같은 결과가 나옵니다.

>> python3 read_csv_data+simple_plot.py3.py
Bitfinex_BTCUSD_1h.csv
Timestamps are UTC timezone,https://www.CryptoDataDownload.com

8 ['Date', 'Symbol', 'Open', 'High', 'Low', 'Close', 'Volume BTC', 'Volume USD']
(15521,) (15521, 4) (15521, 2)
Done to read a CSV file!
Bitfinex
2017-10-09 09:00:00 [ 4575.4  4589.5  4568.6  4585.7] [  6.28890000e+02   2.87889786e+06]
2019-07-18 01:00:00 [ 9617.5  9813.1  9560.3  9748.7] [  5.45670000e+02   5.28719882e+06]


Coinbase_BTCUSD_1h.csv
Timestamps are UTC timezone,https://www.CryptoDataDownload.com

8 ['Date', 'Symbol', 'Open', 'High', 'Low', 'Close', 'Volume BTC', 'Volume USD']
(17919,) (17919, 4) (17919, 2)
Done to read a CSV file!
Coinbase
2017-07-01 11:00:00 [ 2505.56  2513.38  2495.12  2509.17] [  1.14600000e+02   2.87000320e+05]
2019-07-18 01:00:00 [ 9630.    9829.78  9627.08  9795.28] [  7.17030000e+02   6.97910252e+06]


Open: Mean=15.69, RMSD=26.041
High: Mean=20.48, RMSD=31.632
Low: Mean=11.19, RMSD=33.040
Close: Mean=15.98, RMSD=26.180



BTCUSD_price_diff.CoinbasevsBitfinex.png

관련 글들

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 | #02 Moving Average
#03 Read CSV data

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

sct천사의 보팅입니다.
앞으로도 좋은 활동 부탁드려요~~^^

돌봐주셔서(?) 고맙습니다 ^^