파이썬으로 업비트(Upbit) 과거 시세 가져오기(1)

Words
419
Reading
2 min
Listen
Play
9y

Upbit에서 암호화폐 과거 시세를 가져와서 몇 가지 전략을 검증할 계획을 세웠다. Upbit는 현재 공식적으로 API를 지원하지 않는다.

Steemit에서 찾아보니 업비트에서 과거 시세를 가져올 수 있는 방법이 있었다.


위의 글을 참고로 하여 과거 steem의 시세를 받아올 수 있는 프로그램을 파이썬으로 만들어보았다. 굳이 업비트 자료가 필요한 것은 steem을 거래하고 싶었기 때문이다.

결론적으로 업비트에서 스팀달러 일간 과거 가격을 볼 수 있는 html 주소는 아래와 같다. 마지막에 있는 count를 늘리면 원하는 기간만큼의 데이터를 가지고 올 수 있다.
https://crix-api-endpoint.upbit.com/v1/crix/candles/days?code=CRIX.UPBIT.BTC-SBD&count=3

그 결과는 json 형태로 넘어온다.
image.png

이 데이터를 잘 분석하여 우리가 필요로 하는 아래 형태의 데이터를 뽑아주는 파이썬 프로그램을 짜 보는 것이 오늘의 목표이다.
image.png

이 데이터는 아래와 같은 keyword를 이용하면 찾을 수 있다
image.png


위와 같은 json 형태의 데이터 중 원하는 항목만 뽑아주는 프로그램을 만들어보자.

파이썬에서 지원하는 urllib라고 하는 패키지를 이용하면 앞에서 소개한 url에서 나오는 결과를 받아올 수 있다. 그후 받은 값을 json이라고 하는 parsing용 패키지를 이용하면 원하는 데이터 값을 뽑아낼 수 있다. 이 과정을 코딩하면 다음과 같다.

coinName = "steem";
url = 'https://crix-api-endpoint.upbit.com/v1/crix/candles/days?code=CRIX.UPBIT.KRW-' + coinName +'&count=10';
text  = urllib.request.urlopen(url).read()   # url에 있는 데이터 읽기
sdata = bytes.decode(text)  # Byte를 텍스트로 만든다.
data = json.loads(sdata)    # json 구조로 변환
code = data[0]['code']
print(code)
print("==========================================")
print("   date    open high low final    vol")
print("==========================================")
for i in range(len(data))  :
    date = data[i]['candleDateTimeKst']
    onlyDate = date.split('T')     # 날짜정보와 시간정보 분리
    print(onlyDate[0], "%d"%data[i]['openingPrice'], "%d"%data[i]['highPrice'], "%d"%data[i]['lowPrice'], "%d"%data[i]['tradePrice'], "%d"%(data[i]['candleAccTradeVolume']));
print("==========================================")

전체적인 구조는 간단하다. url에 있는 데이터를 읽은 후 json 형태로 변환하여 원하는 데이터만 출력한 것이다.

이 프로그램의 문제는 업비트에 시세 데이터를 요청하는 함수가 실패하는 경우에 대한 대응 코드가 없다는 것이다. 원인은 정확하게 모르겠으나, 업비트의 서버가 단위 시간 당 처리하는 용량의 제한 때문으로 보인다.

코드를 조금 수정하여 실패하면 5초간 휴식을 한 후 다시 요청하는 코드로 변경해 보자. 사실 프로그래밍이 어려운 것은 이런 예외 처리를 많이 하여야 하기 때문이다. 위에서 보여준 코드는 누구나 만들 수 있지만 발생 가능한 모든 경우에 대하여 모두 대응하는 튼튼한(?) 코드를 만들기에는 상당한 시간과 노하우가 필요하다.

기존에는 url에서 데이터를 가져오는 부분이 한 줄이었지만 다양한 에러에 대한 대응 부분을 넣으면 이렇게 코드가 길어진다. 이 코드가 하는 일은 앞에서 설명한 url에서 원하는 데이타를 받지 못하는 HTTPerror이면 5초 간 쉰 후 다시 시도하는 코드이다.

fail2GetData = False
failCnt = 0
while True:
    try :
        text  = urllib.request.urlopen(url).read()
    except urllib.error.HTTPError as e:
        print('Error code: ', e.code, ' 5초 대기')
        failCnt += 1
        if ( failCnt > 10 ) :
            fail2GetData = True;
            break;
        time.sleep(5)
    except urllib.error.URLError as e:
        print("URL error")
        exit()
    else:
        failCnt += 1
        if ( failCnt > 10 ) :
            fail2GetData = True;
            break;
        time.sleep(5)
        break;
if ( fail2GetData )  :
    print("Fail to access url")
    exit()

일단 이렇게 출력된 결과를 copy하여 엑셀로 복사하면 과거 시세 데이터를 활용한 무언가를 할 수 있는 토대가 만들어졌다. 다음 편에서는 검색한 결과를 엑셀로 저장해 주는 부분까지 추가하여 마무리할 예정이다.

소스코드는 아래 사이트에 올라있으니 참고하시기를
https://github.com/multiwhs/steem-project1/blob/master/PythonUpbitDataGathering.py


tmkor@tmkor 님이 Upbit 데이터를 가져올 때 headers 정보를 넣으면 실패하는 경우가 거의 없다고 알려주셨다. 아래 댓글 참고. 그리고 urllib보다 reqeusts가 더 좋다고 알려주셨다. 그래서 requests를 이용한 코드로 변경하였다.

headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
coinName = "steem";
url = 'https://crix-api-endpoint.upbit.com/v1/crix/candles/days?code=CRIX.UPBIT.KRW-' + coinName +'&count=10';
try:
    res = requests.get(url, headers=headers)
except requests.exceptions.HTTPError as err:
    print (err)
    exit(1)

data = res.json()  # json 구조로 변환

코드도 훨씬 간단해졌고, 시세 정보를 가져오는데 오류가 거의 없어졌다.

소스코드 확인하기
https://github.com/multiwhs/steem-project1/blob/master/PythonUpbitDataGathering-2.py

고마워요 tmkor@tmkor님.. 사랑합니다.


p.s node.js 보다는 파이썬이 확실히 편하군요. urllib 등 처음보는 패키지의 경우에는 사용법을 익히는데 시간이 많이 걸리기는 마찬가지지만요. 코딩하는 방식이 C와 유사하고, 함수 명도 짧아서 좋습니다. 형 변환도 자동으로 되어서 편하네요.

파이썬으로 업비트(Upbit) 과거 시세 가져오기(1) | Ecency