본문 바로가기
파이썬으로 웹 App 작성하기/파이썬으로 Upbit 자동거래하기

파이썬만 사용해서 커스텀 코인 트레이더 웹사이트 만들기 - 0 : 준비단계 (환경 설정, 분봉차트)

by Slate_Knowledge 2023. 4. 6.
728x90

모의투자 시스템 링크(구글 인증을 통해서 모의투자 자동 가입 가능)(찝찝하면 https://temp-mail.org/ 과 같은 임시 메일 서비스를 이용해 가입후 초기 1회 인증하면 이후 해당 아이디로 로그인 가능)

데모 :

 

이전 포스팅(2020.03.16 - [파이썬으로 주식 해보기] - PYTHON과 대신증권 API를 이용한 주식 자동화 입문(1)) 에서는, 대신증권 API를 통해서 자동화 봇을 만들어보려고 했었는데, 아무래도 주식 장이 열리는 낮 시간대에만 테스트가 가능하고 win32 api 하고만 호환되는 구닥다리 API들 때문에 개발에 애를 좀 먹었던 경험이 있다.

반면 코인 거래소들은 주식 거래소와는 다르게 24시간 장이 열려있으며 파이썬 64bit와 호환이 되는 거래 API들을 제공한다. Upbit는 우리나라의 코인 거래소 중 하나로, 거래소를 이용하면 이미 많은 부분의 기능을 편리하게 다룰 수 있지만 자동거래라든지 조건부 트레이딩이라든지 커스텀 기능에 대한 지원을 해주지는 않는다.

Upbit 온라인 거래소에서 제공하는 매수/매도 기본 창

파이썬 기반의 거래 자동화 Tool을 만들기의 연습용 테스트베드로는 코인 거래소가 가장 안성맞춤이라고 할 수 있겠다. 따라서, 본 포스팅 시리즈는 업비트 API를 이용하는 자동 트레이딩 어플리케이션을 주제로 하겠다.

0 - 1. Anaconda3 로 파이썬 환경 준비하기

본인이 별도의 파이썬 실행 환경을 구축하고 있다면 그것을 사용해도 무방하나, 이전에 파이썬에 대한 경험이 없거나 코인 거래만을 위한 환경을 별도로 구축하고 싶다면 anaconda를 사용하는게 현명할 것이다. 

필자는 개인용 컴퓨터에서 수행하기 때문에, windows 기준으로 설치를 진행하지만, 리눅스나 Mac에 대해서도 공식 홈페이지에서 그 설치 방법을 찾아볼 수 있다.

공식 홈페이지를 찾아가서 방법을 찾아보기 귀찮다고 하면, 윈도우는 아래의 텍스트를 긁어서 메모장에 붙여넣은 다음, install.bat 파일로 저장하고 더블클릭하면 D 드라이브의 anaconda3 폴더에 자동으로 2022.10 버전 설치가 수행된다. 다른 곳에 설치하고 싶다면 경로를 수정해주자.(\ 는 ₩ 기호이다)

@echo off

REM Get the 2022.10 version of Anaconda
set anaconda_version=https://repo.anaconda.com/archive/Anaconda3-2022.10-Windows-x86_64.exe

REM Download the Anaconda installation file
echo Downloading Anaconda installation file...
curl -k -o anaconda.exe %anaconda_version%

echo Installing Anaconda to D:\anaconda3
START /B /WAIT anaconda.exe /S /D=D:\anaconda3

REM Add Anaconda to the system PATH
echo Adding Anaconda to the system PATH...
echo "PATH %PATH%;D:\anaconda3\Scripts"

REM Create a Conda environment using the environment.yml file
echo Initializing Anaconda
call conda init cmd.exe
echo Initilized Conda

0 - 2. Anvil for User Interface

2023.03.20 - [분류 전체보기] - Anvil 로 웹 앱 만들어서 배포하기 (1) - Getting Started

 

Anvil 로 웹 앱 만들어서 배포하기 (1) - Getting Started

보통 웹 앱을 만드는 건 프론트엔드, 백엔드의 개발을 요구하는데 이때 각 파트에서 필요한 개발 능력 및 언어상황이 다른 경우가 많아서 1인 개발의 난이도를 높이게 된다. Anvil(링크)은 이러한

doodlrudco.tistory.com

이전 포스팅에서 Anvil에 대해서 다뤘었는데, Anvil은 풀 스택 웹 앱 개발을 쉽게 할 수 있도록 도와주는 툴이다. 본 포스팅 시리즈에서는 Anvil을 통해 커스텀 트레이더 어플리케이션의 User Interface 및 로그인 보안 기능(참고링크)을 개발하고자 한다. 시작하기 전에, 상기 포스팅을 참고해서 예제를 만들어보면 좋고, 아니면 이후 인터페이스 파트에서 다시 소개할 것이므로 당장은 넘어가도 무방하다.

0 - 3. Upbit API 등록하기

가장 먼저, API를 통한 자동거래를 활성화하기 위해 upbit 홈페이지에서 API를 등록한다. 입출금 계좌를 등록하는 등 사전작업들을 완수하고, 마이페이지에서 <Open API 관리> 라고 써있는 버튼을 클릭한다.

버튼을 클릭하면 아래와 같이 API를 사용할 용도와, 접근을 허가할 IP 주소와 등의 정보를 기입하는 란이 나오는데, 

본 어플리케이션에서는 자산조회, 주문조회는 물론 기타 모든 기능이 다 있어야하므로 모든 체크박스에 체크를 한 다음 본인이 주로 사용할 IP주소를 입력하고 발급받기를 클릭한다. 그러면 아래와 같이 화면에 2가지 Key가 뜨는데, 이 중 Secret Key는 이후 다시 확인할 수 없으므로, 안전한 파일에 복사하여 저장해두자. 이후에 활용을 위해서 아래와 같이 저장해두자.

access_key:blahblahblahblahblahblahblahblah
secret_key:blahblahblahblahblahblahblahblah

 

 

위의 확인버튼을 클릭하고 나면, 아래와 같이 API Access Key가 성공적으로 할당된 것을 확인할 수 있다.

위의 표에서 보이는 유효기간을 넘기면 API를 재발급 받아야한다. 일단은 1년 기한이니 크게 신경 쓰지는 않아도 되겠다.

0 - 3. API 발급 확인하기.

본 준비단계 포스팅의 마무리로, 현재 분봉차트를 받아온 다음 이를 파이썬 matplotlib로 출력해보기 및 발급받은 API를 통해서 현재 계좌 정보를 불러와 API가 잘 살아있는지 확인하는 작업을 수행한다. 해당 기능은 이후 자동 거래시 현재 정보를 불러올 때도 사용된다.

가장 먼저, 위에서 설치한 anaconda3의 가상환경을 activate 해주거나, 윈도우의 경우 anaconda 프롬프트를 실행한다.

그런 다음 취향껏 base 환경 그대로를 사용하거나, 아래와 같이 새로운 파이썬 환경을 생성해주자

conda create -n coin_trade python=3.8

1) 일봉차트 가져오기

Upbit API는 다양한 언어로 접근이 가능한 Restful 형상이지만, 본 포스팅에서는 파이썬의 restful request 기능을 위주로만 설명한다.

(1) python에 requests 및 matplotlib 패키지를 설치

python -m pip install requests matplotlib

** 혹은 conda 를 이용해서 설치할 수 도 있다.

conda install -c conda-forge requests matplotlib

이 경우 qt와 같이 matplotlib 백엔드 등 권장 패키지들을 싸그리 깔아서 용량은 좀 많이 차지하지만, 이후 사용 안정성 측면에서는 콘다를 권장한다.

(2) 아래와 같이 requests 패키지를 통한 Rest API 코드 작성

import requests

def get_market_list():
    url = "https://api.upbit.com/v1/market/all?isDetails=true"
    headers = {"accept": "application/json"}
    response = requests.get(url, headers=headers)
    return response.json()

def get_candle_data(market_code, count=200, interval="days"):
    url = f"https://api.upbit.com/v1/candles/{interval}"
    querystring = {"market": market_code, "count": count}
    headers = {"accept": "application/json"}
    response = requests.get(url, headers=headers, params=querystring)
    return response.json()

if __name__ == "__main__":
    market_list = get_market_list()
    for market in market_list:
        if market["market"] == "KRW-BTC":
            print(market)
            print(get_candle_data(market["market"]))

get_market_list로 조회 가능한 모든 시장 정보를 쿼리하고, 이때의 market 정보가 KRW-BTC의 코드를 가지고 있으면 <interval>(기본 days) 간격으로 총  <count>(기본 200)개의 candle chart를 조회하는 코드로, 위의 코드를 chart.py라는 파일에 저장하고 실행하면 아래와 같은 결과를 얻게 된다.

(3) 정보로 candle chart 그리기

위의 결과를 잘 보면, 캔들 정보는 list of dictionary 형식으로 반환된다. 이 때 하나하나의 dictionary는 각 interval 거래 정보를 담고 있는데, 각각의 key는 아래의 정보를 담고 있다.

Key Value
market 시장 코드
candle_date_time_utc UTC 기반 기준 시간
candle_date_time_kst KST(한국표준시) 기반 기준 시간
opening_price 시작가
trade_price 종가
high_price 고가
low_price 저가
timestamp 해당 캔들에서 마지막 틱이 저장된 시각
candle_acc_trade_price 누적 거래 금액
candel_acc_trade_volume 누적 거래량
prev_closing_price 전일 종가
change_price 전일 종가 대비 변화 금액
change_rate 전일 종가 대비 변화량

이 중 우리는 시가, 종가, 고가, 저가, 거래일만 가지고 차트를 그린다.

import requests
import numpy as np
import matplotlib.pyplot as plt

def get_market_list():
    url = "https://api.upbit.com/v1/market/all?isDetails=true"
    headers = {"accept": "application/json"}
    response = requests.get(url, headers=headers)
    return response.json()

def get_candle_data(market_code, count=200, interval="day"):
    url = "https://api.upbit.com/v1/candles/days"
    querystring = {"market": market_code, "count": count}
    headers = {"accept": "application/json"}
    response = requests.get(url, headers=headers, params=querystring)
    return response.json()

def plot_candle_chart(data, market_code):
    dates = [d['candle_date_time_kst'].split('T')[0].split('-')[-1] for d in data]
    opens = np.array([d['opening_price'] for d in data])
    highs = np.array([d['high_price'] for d in data])
    lows = np.array([d['low_price'] for d in data])
    closes = np.array([d['trade_price'] for d in data])

    colors = ['green' if opens[i] < closes[i] else 'red' for i in range(len(data))]

    fig, ax = plt.subplots()
    ax.bar(dates, highs-lows, bottom=lows, color=colors, width=0.8, edgecolor='black')
    ax.vlines(dates, lows, highs, color='black', linewidth=1)
    ax.scatter(dates, opens, color=colors, marker='.', edgecolors='black')

    ax.set_title('Candle Chart for ' + market_code)
    ax.set_xlabel('Date')
    ax.set_ylabel('Price')

    plt.show()
    
if __name__ == "__main__":
    market_list = get_market_list()
    for market in market_list:
        if market["market"] == "KRW-BTC":
            plot_candle_chart(get_candle_data(market["market"],count=20), market["market"])

이제, 이전의 코드를 위와 같이 candle chart를 그리도록 바꿔준다. 주어진 데이터에 대해서 일별로 최대와 최소 사이의 bar와 시작가에 검은 점, 그리고 bar의 색의 경우 시작가가 종료가보다 낮은 경우 녹색, 반대의 경우 적색으로 그리게 된다.

상기 코드를 다시 실행해보면 아래와 같은 일봉차트가 잘 그려지는걸 확인할 수 있다.

2) 계정 정보 쿼리하기

API를 사용해서 가장 기본적인 전체 계좌 정보를 조회하는 것으로 본 포스팅을 마무리한다.

아까 API Key를 생성하면서 저장해둔 secret key 및 access key가 이제부터 사용되는데, 이 정보를 request header에 포함시키기 위해 jwt라는 패키지가 추가로 필요하다. 따라서 아래와 같이 설치해주자. (import  할 때는 jwt이지만, 설치는 pyjwt를 해야한다! 혼동 주의)

python -m pip install pyjwt

그 다음, 아래의 코드를 accounts.py와 같이 저장한 다음 실행해준다. 아까 저장해 둔 api_keys 텍스트 파일의 위치를 key_file_path에 할당해주면 실행이 문제없이 진행된다.

import jwt
import os
import requests
import uuid
from urllib.parse import urlencode, unquote

key_file_path = '../secret_api_keys.txt'
access_key, secret_key = [k.split(':')[-1] for k in open(key_file_path).read().split('\n')]
server_url = 'https://api.upbit.com'

def get_my_accounts():
  payload = {
      'access_key': access_key,
      'nonce': str(uuid.uuid4()),
  }
  jwt_token = jwt.encode(payload, secret_key)
  authorization = 'Bearer {}'.format(jwt_token)
  headers = {
    'Authorization': authorization,
  }

  res = requests.get(server_url + '/v1/accounts', params=None, headers=headers)
  return res.json()

if __name__ == "__main__":
  print(get_my_accounts())

빠트린 부분 없이 따라왔을 경우 아래와 같이 나의 현재 잔고를 확인할 수 있다.

728x90
반응형

댓글