본문 바로가기

가상화폐 시리즈

[PyQt6] 가상화폐 알고리즘 매매 프로그램(2) - 보유코인 조회

728x90

pybithumb API를 사용해서 보유잔고를 조회하는 방법은 다음과 같습니다.

*ConnKey와 SecKey는 개별적으로 발급받아야 합니다.

from pybithumb import Bithumb

ConnKey = "___" #발급받은 api key
SecKey = "___"

bithumb = Bithumb(ConnKey, SecKey)

for coin in Bithumb.get_tickers():
    print(coin, bithumb.get_balance(coin))

 

tuple의 각 값은 (보유코인, 사용 중 코인, 보유원화, 사용중원화)입니다.

현재 제가 5만 원의 잔고를 원화로 넣어둔 상태입니다.

 

이제 코인 정보를 담아서 QListWidget에 추가하는 프로그램을 짜보려고 합니다.

UI는 위 이미지처럼 구현하고 조회버튼을 누르면 잔고를 조회해 뿌려줍니다.

 

class MyWindow(QWidget):
    def __init__(self):
        super().__init__()
        
    def initUI(self):
        self.setWindowTitle("CoinBot") #프로그램 상단의 이름입니다. 위 이미지를 캡쳐할 때와는 상이함.
        container = QHBoxLayout()
        self.budgetListWidget = QListWidget()

        container.addWidget(self.budgetListWidget)

        startBtn = QPushButton("조회")
        startBtn.clicked.connect(self.startBtnClicked) #버튼 클릭 이벤트

        container.addWidget(startBtn)

        self.setLayout(container)
        
    def startBtnClicked(self):
        myCoins = self.getMyBudget()
        for coin in myCoins:
            self.budgetListWidget.addItem(QListWidgetItem(str(coin)))

    def getMyBudget(self):
        bithumb = Bithumb(ConnKey, SecKey) #로그인
        myCoins = []
        for coin in Bithumb.get_tickers():
            budget = bithumb.get_balance(coin)
            myCoins.append(budget)
        
        return myCoins

    

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyWindow()
    window.initUI()
    screen = app.primaryScreen()
    size = screen.size()
    w, h = 600,400
    window.setGeometry(int(size.width()/2-w/2), int(size.height()/2-h/2), w,h)
    window.show()

    app.exec()

 

하지만 위 소스대로 하면 모든 코인 정보를 조회한 다음에 내가 보유한 코인을 찾아야 하는 불필요한 루프를 돌아야 되기 때문에 시간이 다소 소요됩니다. pybithumb에서 제공하는 방식이 아닌 빗썸에서 제공하는 api를 사용해 봅시다.

 

빗썸 API

잔고를 조회하는 API는 개인정보가 포함되어 있기 때문에 인증 헤더를 같이 보내야 하는 번거로움이 있습니다.

https://apidocs.bithumb.com/docs/%EC%9D%B8%EC%A6%9D-%ED%97%A4%EB%8D%94-%EB%A7%8C%EB%93%A4%EA%B8% B0

 

인증 헤더 만들기

인증 헤더 만들기Private API 요청 시 발급받은 Connect Key와 Secret Key를 이용하여 4개의 파라미터를 헤더에 추가하여 전송합니다. 요청 변수설명타입api-client-typeApi-Sign 생성 시 사용하는 구분자 유형"0

apidocs.bithumb.com

위 Document를 참조하여 아래와 같은 파이썬 클래스를 하나 만듭니다.

import time
import math
import base64
import hmac, hashlib
import urllib.parse
import requests

class XCoinAPI:
	api_url = "https://api.bithumb.com";
	api_key = "";
	api_secret = "";

	def __init__(self, api_key, api_secret):
		self.api_key = api_key;
		self.api_secret = api_secret;

	def body_callback(self, buf):
		self.contents = buf;

	def microtime(self, get_as_float = False):
		if get_as_float:
			return time.time()
		else:
			return '%f %d' % math.modf(time.time())

	def usecTime(self) :
		mt = self.microtime(False)
		mt_array = mt.split(" ")[:2];
		return mt_array[1] + mt_array[0][2:5];

	def xcoinApiCall(self, endpoint, rgParams):
		# 1. Api-Sign and Api-Nonce information generation.
		# 2. Request related information from the Bithumb API server.
		#
		# - nonce: it is an arbitrary number that may only be used once.
		# - api_sign: API signature information created in various combinations values.

		endpoint_item_array = {
			"endpoint" : endpoint
		}

		uri_array = dict(endpoint_item_array, **rgParams) # Concatenate the two arrays.

		str_data = urllib.parse.urlencode(uri_array)

		nonce = self.usecTime()

		data = endpoint + chr(0) + str_data + chr(0) + nonce
		utf8_data = data.encode('utf-8')

		key = self.api_secret
		utf8_key = key.encode('utf-8')

		h = hmac.new(bytes(utf8_key), utf8_data, hashlib.sha512)
		hex_output = h.hexdigest()
		utf8_hex_output = hex_output.encode('utf-8')

		api_sign = base64.b64encode(utf8_hex_output)
		utf8_api_sign = api_sign.decode('utf-8')

		headers = {
			"Accept": "application/json",
			"Content-Type": "application/x-www-form-urlencoded",
			"Api-Key": self.api_key,
			"Api-Nonce": nonce,
			"Api-Sign": utf8_api_sign
		}

		url = self.api_url + endpoint

		r = requests.post(url, headers=headers, data=rgParams)
		return r.json()

 

이 클래스를 호출하여 API에 잔고를 요청해 봅시다.

ConnKey = "___" 
SecKey = "___"
coinapi = XCoinAPI(ConnKey,SecKey)
rgParams = {
    'endpoint': '/info/balance',  #<-- endpoint가 가장 처음으로 와야 한다.
    "currency": "ALL",
}

coinapi.xcoinApiCall(rgParams['endpoint'],rgParams)

 

위 json에서 available_[currency] 값이 0이 아닌 애들만 필터링하면 그게 보유잔고가 될 겁니다.

 

def startBtnClicked(self):
    myCoins = self.getMyBudget()
    for coin in myCoins:
        self.budgetListWidget.addItem(QListWidgetItem(str(coin)+str(myCoins[coin])))

def getMyBudget(self):
    CoinApi = XCoinAPI(ConnKey, SecKey)
    rgParams = {
        'endpoint': '/info/balance',  #<-- endpoint가 가장 처음으로 와야 한다.
        "currency": "ALL",
    }
    coins = CoinApi.xcoinApiCall(rgParams['endpoint'], rgParams)
    ######
    coinsHas = dict((key,value) for key, value in coins['data'].items() if key.startswith('available_') and float(value) > 0)
    ######
    return coinsHas

getMyBudget 함수만 빗썸 api를 사용하는 부분으로 수정했고 coinHas라는 변수는 전체 코인들 중 잔고를 보유한 코인만 필터링하여 담습니다. 

 

속도가 훨씬 빨라서 앞으로도 잔고 조회를 할 때는 이 방식을 활용하려 합니다.