암호화폐는 탈중앙화 화폐이기 때문에 거래소마다 가격의 차이가 있다.
따라서 거래소마다 가격이 다른 것을 이용해 가격이 싼 곳에서 구매한 뒤 비싼곳에서 사면 적은 리스크로 돈을 벌 수 있고 이것을 무위험 차익거래 혹은 재정거래라고 부른다.
돈을 입금하면 재정거래를 자동으로 수행해주는 일부 서비스가 있지만, 수수료가 매우 크고 서비스 자체가 폐업해버리면 자산을 잃을 수 있기에 파이썬을 활용하여 재정거래 시스템을 직접 구축해보기로 했다.
제대로 돈을 벌기 위해서는 시중에 존재하는 대부분의 거래소를 탐색하여 가장 가격차이가 큰 두곳을 타겟으로 해야겠지만, 사람이 거래를 하는것과 달리 API를 이용한 프로그래밍 방식은 보안 절차가 상당히 까다로우며 시간이 많이 걸린다. 따라서 이번에는 업비트와 바이낸스 두 거래소를 타겟으로 하여 간단히 진행해본다.
우선 두 거래소 모두 아래 절차를 진행한다.
1. 거래에서 사용할 API 주소 발급 과정
2. 출금이 가능한 지갑 주소(Whitelist)를 등록
1번은 자료가 많기에 생략한다. 2번의 경우 API를 이용해 제 3자에게 암호화폐가 출금되는 상황은 위험하기에, 본인의 지갑 주소로 검증이 된 주소로만 화폐 전송을 허가하기 위함이다. 이는 휴대폰 인증을 통해서 등록하는 절차를 각 거래소마다 필수적으로 진행해주어야 한다.
바이낸스와 업비트에서 출금이 가능한 주소를 직접 등록하게 되면, API를 통한 거래시 해당 주소로 출금이 가능해진다. 주소를 등록할때 휴대폰 인증을 통한 절차가 두 플랫폼 모두에 존재했기 때문에 꽤 안전하다고 느껴진다.
API를 활용한 수월한 거래를 위해 각 거래소에서 제공하는 API기능을 적극 활용한다. 이때, 주요 기능이 잘 구현된 라이브러리를 활용하면 수월하게 작업이 가능하다. 설치 명령어는 다음과 같다.
pip3 install python-binance
pip3 install pyupbit
pip3 install upbit-client
이후 본인의 API키를 .env파일에 잘 저장해준 뒤, 작업 파일에서 각 라이브러리를 임포트하고, API키를 불러와서 거래소 클라이언트 객체를 생성하는 과정은 다음과 같다.
import time
import csv
import os
import requests # 환율 조회용
import pyupbit # 가격 데이터 조회용
from binance.client import Client # 바이낸스 API 사용
from binance.exceptions import BinanceAPIException
from upbit.client import Upbit as UpbitClient # Upbit 공식 클라이언트
from dotenv import load_dotenv
# API KEY 정보로드
load_dotenv()
# ===== API Key/Secret =====
BINANCE_API_KEY = os.environ.get('BINANCE_API_KEY')
BINANCE_API_SECRET = os.environ.get('BINANCE_API_SECRET')
UPBIT_ACCESS_KEY = os.environ.get('UPBIT_ACCESS_KEY')
UPBIT_SECRET_KEY = os.environ.get('UPBIT_SECRET_KEY')
# ===== 거래소 클라이언트 객체 생성 =====
binance_client = Client(BINANCE_API_KEY, BINANCE_API_SECRET)
upbit_client = UpbitClient(UPBIT_ACCESS_KEY, UPBIT_SECRET_KEY)
여기까지 큰 문제 없이 진행되었다면, 아래 코드를 이용하여 본인 거래소 계좌에 있는 암호화폐 정보를 출력할 수 있을 것이다.
# -------------------------------
# 1. 각 거래소 잔고 출력
# -------------------------------
def print_upbit_balance():
try:
# Upbit 공식 클라이언트의 Account_info() 메서드를 사용하여 잔고 정보 조회
resp = upbit_client.Account.Account_info()
print("==== Upbit 잔고 정보 ====")
for asset in resp['result']:
balance = float(asset.get("balance", 0))
if balance > 0:
print(f"{asset['currency']}: {balance}")
except Exception as e:
print("Upbit 잔고 출력 오류:", e)
def print_binance_balance():
try:
# Binance의 계좌 정보를 조회하여 각 자산별 잔고 출력
account_info = binance_client.get_account()
print("==== Binance 잔고 정보 ====")
for asset in account_info['balances']:
free = float(asset.get('free', 0))
locked = float(asset.get('locked', 0))
total = free + locked
if total > 0:
print(f"{asset['asset']}: {total} (free: {free}, locked: {locked})")
except Exception as e:
print("Binance 잔고 출력 오류:", e)
# -------------------------------
# 2. 보유 코인 목록 및 양 출력
# -------------------------------
def print_upbit_coin_holdings():
try:
resp = upbit_client.Account.Account_info()
print("==== Upbit 보유 코인 목록 ====")
for asset in resp['result']:
currency = asset.get("currency")
# KRW는 기본 자산이므로 코인 목록에서는 제외할 수 있음 (필요 시 출력)
if currency != "KRW":
balance = float(asset.get("balance", 0))
if balance > 0:
print(f"{currency}: {balance}")
except Exception as e:
print("Upbit 코인 보유량 출력 오류:", e)
def print_binance_coin_holdings():
try:
account_info = binance_client.get_account()
print("==== Binance 보유 코인 목록 ====")
for asset in account_info['balances']:
asset_name = asset.get("asset")
# USDT와 같이 기본 자산은 제외할 수 있음 (필요 시 출력)
if asset_name != "USDT":
free = float(asset.get("free", 0))
locked = float(asset.get("locked", 0))
total = free + locked
if total > 0:
print(f"{asset_name}: {total} (free: {free}, locked: {locked})")
except Exception as e:
print("Binance 코인 보유량 출력 오류:", e)
print_upbit_balance()
print_binance_balance()
print_upbit_coin_holdings()
print_binance_coin_holdings()
다음은 각 거래소 클라이언트 객체를 이용해 원하는 코인을 매수하는 코드 예시다.
resp = upbit_client.Order.Order_new(
market=symbol,
side='bid', # bid : 매수 , ask : 매도
#volume='10', # 주문량
price='30', # 주문 가격
ord_type='price' # limit: 지정가 주문, price: 시장가 주문 (매수), market: 시장가 주문 (매도)
)
print(resp['result'])
위 코드를 실행하면 현재 시장가격대로 30개를 매수하게 된다. 하지만 위 방법을 사용하는것은 비추천한다. 왜냐하면 업비트의 가격 산출 방식에 심각한 문제가 있기 때문이다.
아래 사진을 보자. 화면에 나와있는 대로 API를 통해 시장가 조회를 하거나 업비트 홈페이지에서 현재 가격을 확인하면 0.4269 USDT인 것을 확인할 수 있다. 하지만 우측 하단을 보면 꽤 오래전부터 가격이 0.3 USDT 이하로 유지되고 있었음을 알 수 있다.
이로 인해 당시 가치보다 지나치게 비싸게 코인이 매수되어 손실을 보게 되었다.
암호화폐를 매수할 때는 지정가로 구매하도록 하자. 지정가를 이용해서 구매하는 코드는 아래와 같다.
resp = upbit_client.Order.Order_new(
market=symbol,
side='bid', # bid : 매수 , ask : 매도
volume='10', # 주문량
price='0.26', # 주문 가격
ord_type='price' # limit: 지정가 주문, price: 시장가 주문 (매수), market: 시장가 주문 (매도)
)
print(resp['result'])
이후 API를 통한 거래가 가능하도록 출금 주소가 Whitelist에 잘 등록되었는지 확인하는 절차를 진행한다.