[투자] 첫 바이낸스 거래소에서의 암호화폐 선물 거래

제가 오늘 홍콩의 암호화폐 거래소인 바이낸스(Binance)에서 첫 선물 거래를 개시해보았습니다. 선물 계좌 개설은 클릭 하나면 가능하더라고요. 즉시 최대 125배 레버리지까지 가능한 계좌를 받게 되었습니다. 다만, 제 리스크 회피성 투자성격상 125배의 레버리지를 제정신이라면 모두 사용하는 일은 없을 것 같습니다. 그래서, 선물거래를 시작하는 제게 암호화폐 시장에 대한 이제까지의 개인적인 판단은 다음과 같습니다. 아, 그에 앞서서 저는 암호화폐를 블록체인 기술의 파생이 아닌 하나의 트레이딩 가능한 상품의 관점에서 접근하고 있다는 점을 먼저 말씀드리고 싶습니다. 사실 블록체인 기술이 하이프 사이클(Hype-Cycle) 속에서 너무나도 고평가 되어있고, 블록체인의 분산화 기술이 중앙화된 데이터 센터를 과연 대체할 수 있을까하는 생각을 지울 수가 없거든요.

1. 비트코인만이 VIX 지수와 동기화되어 안전자산의 역할을 한다.
다만, 이 부분은 제가 데이터 분석을 통해서 회귀분석으로 실질적인 결정계수값을 구해봐야 알 수 있을 것 같습니다. 아직까지는 제 심리적인 추측입니다. 이전에도 그렇고, 어제에도 이란의 솔레이마니 사령관에 대한 미국의 공습이 파장을 일으키면서 급격한 상승장을 보여주고 있습니다. 분명 시장의 공포심리와 일정정도 상관관계가 있을 것으로 생각하고 있습니다.

2. 알트코인은 비트코인을 후행한다
어떻게 보면 당연한 얘기이지만, 특정 코인들은 그러한 성향을 더 많이 보이더라고요. 나중에 이 부분도 데이터 분석을 통해, 타임프레임을 쪼개서 비트코인과 상관관계를 보면서 가격추이를 후행하는 코인 몇개를 선정해서 트레이딩하는 것도 괜찮을 것 같습니다.

3. 암호화폐 시장에서 뉴스 트레이딩보다 차트 기반 트레이딩이 유효하다
물론 위에서 말한 시장 전체에 영향을 줄만한 뉴스들은 암호화폐 시장에 큰 영향을 줍니다. 하지만, 개별 코인들의 작은 호재들은 큰 영향을 주지 못하는 것 같습니다. 워낙 가짜 전문가들과 트위터발 가짜뉴스가 많은 판이라서 그런걸까요. 하여튼, 차트 중심의 접근이 더욱 유효해보입니다. 이점은 데이터 분석을 하는 입장에서는 유리한 점입니다. 가격 데이터만 분석해도 충분하다는 뜻이니깐요.

여기까지는 일반적인 암호화폐 트레이딩에서도 적용되는 점들입니다. 이러한 생각을 바탕으로, 저는 선물거래에서는 적정한 레버리지(5배 ~ 10배)를 바탕으로 1분 ~ 5분봉 차트를 기반으로 단타를 할 예정입니다. 암호화폐 선물투자에서 포지션을 오래 가져가기에는 리스크가 많이 클 것 같더라고요. 다만 단타를 시작하려 보니 수수료가 문제이네요. 그래도 최대한 많은 트레이딩을 통해서 경험을 익히고, 거래빈도수를 높혀서 수익 가능성을 최대한 높혀보고자 합니다. 아직까지는 초보 트레이더로써, 수익률은 양수값만 된다면 그 이후에는 적중률(Hit Ratio)로 제 성과를 평가해보고자 합니다.

아, 그리고 아침에 하는 선물 트레이딩이 생각보다 괜찮네요. 현실에서 기분이 이상하고 무언가 나쁜 것 같은 순간에 하는 것도 좋습니다. 선물 트레이딩이 아드레날린과 도파민을 자극하는 것 같습니다. 제대로 된 트레이더라면 이런걸 느낄게 아니라 트레이딩에 집중해야 하지만, 저는 아직 초보이니깐요. 이렇게나마 도박사의 심리로 스릴넘치는 순간을 즐기면서 행복감을 느껴보고자 합니다.

[기술] Binance 암호화폐 자산 현황을 파이 차트로 만들기

최근에 제 자산이 어떻게, 얼마나, 어느 비중만큼 있는지 다시 확인하는 작업을 하고 있었습니다. 사실 지난 고등학교 3년동안 투자는 해놓고선, 정작 자산이 어떻게 변동되는지 살펴보지 않았던게 사실입니다. 체크카드로 긁을 때마다 날라오는 통장 잔고만 보고선, 충분하다 생각하면 넘어가는 경우가 대부분이였죠.

이제서야 정신차리고 확인해보니, 암호화폐와 미국 증시는 대폭락장을 겪고 있었습니다. 세상은 변하는데 내 포트폴리오는 과거에 머물고 있었던 거죠. 당연히 리스크 헷지 같은 것이 될리가 없었고, 그대로 손실을 껴안고 있었습니다. 더 이상 이럴순 없다는 생각에, 주기적으로 자산 현황을 추적하는 일을 해야겠다는 생각이 들었습니다.

특히, 가장 시급한건 변동성이 큰 암호화폐였습니다. 대충 코딩을 해서라도, 내가 어떤 코인을 얼마나 가지고 있는지 시각화 해서 결과를 알아보고 싶어서 작업을 바로 시작하게 되었습니다.

 

Binance API로 데이터 가져오기

올해 봄 즈음, 나름 알고리즘 트레이딩에 관심이 많아 Binance API를 만지작거린 경험이 있었습니다. 이동평균선 크로스와 볼린저 밴드를 이용한, 아주 단순한 알고리즘이었고, 당연히 수익은 내지 못했습니다. 그래도 잘 보관해놔서, 이번에 빠르게 꺼내다 쓸 수 있었습니다.

패키지 불러오기 및 설정
Binance API 데이터를 가져오기 위해 python-binance 패키지를 사용했습니다. 패키지 설명서는 여기서 확인할 수 있습니다. 사실 RESTful API를 통해서 직접 POST해서 가져올 수도 있지만, 이미 좋은 패키지가 있는데 그럴 이유가 전혀 없었습니다. 아무튼, 필요한 패키지들을 불러오고선 기본적인 설정들을 해줬습니다.

from binance.client import Client
import warnings
warnings.filterwarnings("ignore")
from matplotlib import pyplot as plt


그다음에는 가장 기본적으로 Client()에 API Key와 Secret 키를 입력해줘서 접근 권한을 얻도록 해줬습니다. 너무 빨리 타임아웃이 발생하지 않도록 넉넉히 100ms으로 잡아뒀습니다.

client = Client('Binance API Key', 'Binance Secret Key', {"verify": False, "timeout": 100})


비트코인 최근 가격 불러오기

이제부터 다양한 정보들을 직접 불러오는데, 가장 먼저 비트코인의 최신 가격을 불러왔습니다. 방법은 간단하게, 1분 단위 OHLCV Kline 과거 데이터 중에서 가장 최근 Close 가격을 가져오도록 해두었습니다. 즉, 가장 최근의 가격 정보를 쿼리하는 것입니다.

BTCPrice = float(client.get_klines(symbol='BTCUSDT',
                            interval=client.KLINE_INTERVAL_1MINUTE,
                            limit=1,
                            requests_params={'timeout':100})[0][4])


참고로 OHLCV 정보가 list in list 형태로 제공되기 때문에, 적절히 리스트에서 골라 써야 합니다.
[0]을 통해서 첫번째이자 유일한 값에 접근하고, [4]로 1분 봉 마감가격인 Close에 접근했습니다.

# get_klines 출력값
[[
1499040000000, # Open time
"0.01634790", # Open
"0.80000000", # High
"0.01575800", # Low
"0.01577100", # Close -> List[0][4]
"148976.11427815", # Volume
1499644799999, # Close time
"2434.19055334", # Quote asset volume
308, # Number of trades
"1756.87402397", # Taker buy base asset volume
"28.46694368", # Taker buy quote asset volume
"17928899.62484339" # Can be ignored
]]


Binance 자산 현황을 불러 데이터 전처리하기

그 다음에는 내 Binance 거래소 지갑에 있는 자산 현황을 불러온다. 간단하게 get_account()를 통해 내가 가지고 있는 코인들과 잔고 수량을 확인할 수 있습니다. 자산 현황 정보는 dict in list in dict 형태로 주기 때문에, 적절히 내가 보유한 코인들과 잔고 수량을 볼 수 있게 접근해줘야 합니다.

AssetBalance = client.get_account()
#get_account 불러오기 샘플
{'makerCommission': 10,
'takerCommission': 10,
'buyerCommission': 0,
'sellerCommission': 0,
'canTrade': True,
'canWithdraw': True,
'canDeposit': True,
'updateTime': 1539110138808,
'balances': [{'asset': 'NEO', 'free': '0.00000000', 'locked': '0.00000000'}, {'asset': 'LTC', 'free': '0.00000000', 'locked': '0.00000000'}...]


간단하게는 Dict[‘balances’]로 먼저 접근하고선, for문으로 개별 딕셔너리를 조회하는 방법이 있습니다. 여기서 if절로 잔고 수량이 0 이상인 코인들만 거른 다음에 AvailableAsset이라는 리스트에 저장시켜줬습니다.

AvailableAsset = []
for Asset in AssetBalance['balances']:
    if float(Asset['free']) > 0:
        AvailableAsset.append(Asset)


그 다음에는 for문으로 AltPricePair라는 딕셔너리에 {코인명 : 코인 잔고 수량} 페어를 만들어 저장시켜줬습니다. 이를 위해, PairName에 000BTC 형식으로 환율 거래쌍 이름을 만들어 검색했습니다. 여기서 문제는 BTCBTC나 USDTBTC와 같은 거래쌍은 없는지라, 그대로 돌리면 BTC 잔고를 검색하려다 ‘그런 거래쌍은 없다’라는 에러가 뿜어져 나옵니다. 이를 해결하기 위해서, try-except문을 이용해서 에러가 나타나면 바로 패스하도록 만들었습니다.

이렇게 거래쌍을 통해 OHLCV 값을 불러오면, 해당 코인의 비트코인 기준 가격이 나옵니다. 이걸 해당 코인 수량만큼 곱해주면, 잔고 금액이 비트코인 기준으로 얼마나 있는지 알 수 있습니다. 하지만 우리는 비트코인보다 미국 달러가 익숙하기 때문에, 이전에 BTCPrice에 불러온 비트코인 가격을 여기다 곱해주면 미국 달러 기준 잔고량으로 변환 가능합니다. 이 값을 AltPricePair딕셔너리에 키-벨류 페어로 저장시켜 주도록 했습니다.

AltPricePair = {}
for Asset in AvailableAsset:
    PairName = Asset['asset'] + 'BTC'
    try:
        MinuteKlineRaw = client.get_klines(symbol=PairName,
                                           interval=client.KLINE_INTERVAL_1MINUTE,
                                           limit=1,
                                           requests_params={'timeout': 100})
        CurrentPrice = MinuteKlineRaw[0][4]
        AltPricePair[Asset['asset']] = float(CurrentPrice) * float(Asset['free']) * BTCPrice
    except:
        continue


이전에 BTCBTC나 USDTBTC와 같은 환율 거래쌍은 존재하지 않아 불러올 수 없다고 했습니다. 그렇다고 비트코인이나 미국 달러 자산 값을 빼고 알트코인들의 가치만 더할 수는 없습니다. 다행히도, get_asset_balance()라고 개별 코인에 대한 잔고 수량을 불러오는 함수가 있습니다. 비트코인은 잔고 수량을 불러서, 비트코인의 미국 달러 가격에 곱해줘서 잔고 금액을 MyBTCBalance에 저장합니다. 미국 달러화는 당연히 잔고 수량이 잔고 금액과 동일하니, 그대로 사용해 MyUSDTBalance에 저장합니다. 그리고 가장 중요한 알트코인의 가격, AltPricePair에 수많은 키-벨류 페어에서 values()를 통해 벨류 값들의 리스트를 구합니다. 그리고선 바로 sum()으로 그 합들을 MyAltBalance에 저장합니다.

마지막으로 MyBTCBalance, MyUSDTBalance, MyAltBalace 이 셋을 모두 더해주면, 내 Binance 자산의 총 합계를 미국 달러화 기준으로 볼 수 있습니다.

MyBTCBalance = BTCPrice * float(client.get_asset_balance('BTC')['free'])
MyUSDTBalance = float(client.get_asset_balance('USDT')['free'])
MyAltBalance = sum(AltPricePair.values())


먼저 AltPricePair에 있는 {코인명: 코인의 미국 달러 기준 잔고 금액} 딕셔너리 페어처럼, 비트코인과 미국 달러화도 똑같이 업데이트하여 저장해줍니다. 그러고선 혼동이 없도록, 이렇게 업데이트된 딕셔너리를 PricePair이라고 다시 이름 지어줍니다.

AltPricePair.update({'BTC' : MyBTCBalance})
AltPricePair.update({'USDT' : MyUSDTBalance})
PricePair = AltPricePair

 

 

Matplotlib으로 파이 차트 만들기

이제 데이터 전처리가 끝났으니, 자산의 코인별 비중을 시각화 시켜야합니다.
PricePair 딕셔너리에 코인명을 담고 있는 키 부분을 keys()를 통해, PriceKey에 리스트 형태로 저장한다. 또한, 코인의 미국 달러 기준 잔고 금액이 담겨있는 벨류 부분은 PriceValue에 values()로 리스트 형태로 저장합니다. 그러고선, 다시 PriceValue는 for문으로 소수점 2자리 이하 값으로 반올림을 시켜 예쁘게 만들어줍니다. 그럼 각각의 PriceKey와 PriceValue가 순서에 맞게 정갈한 리스트를 내놓습니다.

PriceKey = PricePair.keys()
PriceValue = PricePair.values()
PriceValue = [round(elem, 2) for elem in PriceValue]
#PriceKey와 PriceValue 리스트
dict_keys(['BNB', 'GAS', 'BAT', 'XRP', 'XLM', 'BTC', 'USDT'])
[0.04, 0.0, 212.14, 219.99, 129.67, 165.62, 0.0]


마지막으로 Matplotlib의 pie()를 통해 플롯해주는데, 그냥 PriceValue만 넣으면 아무 것도 없는 밍밍한 파이 차트가 나옵니다. 여기에 퍼센테이지를 값과 실제 잔고 금액을 표시하고 싶었습니다. 퍼센테이지는 autopct에 적당히 설정해주면 되지만, 실제 잔고 금액은 어떻게 넣나 고민이 많았습니다. 결국 Stackoverflow에 한 함수를 끌어와서, 잘 모르지만 일단 사용하게 됬습니다.

def make_autopct(values):
    def my_autopct(pct):
        total = sum(values)
        val = int(round(pct*total/100.0))
        return '{p:.2f}%  ({v:d})'.format(p=pct,v=val)
    return my_autopct


이걸 autopct에 넣어주고선, 레전드를 설정해줬더니 투박하지만 제 역할은 하는 파이 차트를 결국 띄울 수 있었습니다.

Binance 자산의 코인별 비중 현황 파이 차트

 

전체코드

from binance.client import Client
import warnings
warnings.filterwarnings("ignore")
from matplotlib import pyplot as plt

client = Client('A94G89HZGqMF8niazexzsN7Vo8ygzVmvxAFbxtYH6IossrzIAtuPTgoj1k4iAXyq', 'wG18VxuQjGb8F33opQKJQX6EmWMuz0cwZPEh4aYTjxYmOF6NBNasUys5G6sEvOGa', {"verify": False, "timeout": 100})

BTCPrice = float(client.get_klines(symbol='BTCUSDT',
                            interval=client.KLINE_INTERVAL_1MINUTE,
                            limit=1,
                            requests_params={'timeout': 100})[0][4])

AssetBalance = client.get_account()
print(AssetBalance)

AvailableAsset = []
for Asset in AssetBalance['balances']:
    if float(Asset['free']) > 0:
        AvailableAsset.append(Asset)

AltPricePair = {}
for Asset in AvailableAsset:
    PairName = Asset['asset'] + 'BTC'
    try:
        MinuteKlineRaw = client.get_klines(symbol=PairName,
                                           interval=client.KLINE_INTERVAL_1MINUTE,
                                           limit=1,
                                           requests_params={'timeout': 100})
        CurrentPrice = MinuteKlineRaw[0][4]
        AltPricePair[Asset['asset']] = float(CurrentPrice) * float(Asset['free']) * BTCPrice
    except:
        continue



MyBTCBalance = BTCPrice * float(client.get_asset_balance('BTC')['free'])
MyUSDTBalance = float(client.get_asset_balance('USDT')['free'])
MyAltBalance = sum(AltPricePair.values())

AltPricePair.update({'BTC' : MyBTCBalance})
AltPricePair.update({'USDT' : MyUSDTBalance})

PricePair = AltPricePair

PriceKey = PricePair.keys()
PriceValue = PricePair.values()
PriceValue = [round(elem, 2) for elem in PriceValue]

print(PriceKey)
print(PriceValue)

def make_autopct(values):
    def my_autopct(pct):
        total = sum(values)
        val = int(round(pct*total/100.0))
        return '{p:.2f}%  ({v:d})'.format(p=pct,v=val)
    return my_autopct

plt.pie(PriceValue, labels=PriceKey, autopct=make_autopct(PriceValue))
plt.legend(PriceKey)
plt.show()

print(MyAltBalance + MyUSDTBalance + MyBTCBalance)

 

 

배운점

먼저, 코딩도 당분간 두통 때문에 그만둬야겠습니다. 정말 모니터 앞에 오래 앉아있으면 심한 번아웃이 옵니다. 블루라이트 때문인가도 싶습니다. 파이썬의 문법 면에서 배운점은, 딕셔너리는 리스트처럼 + 만으로 합쳐지지 않는다는 것입니다. 기존의 딕셔너리에 update()로 새 딕셔너리를 업데이트하여 더해줘야 합니다.

마지막으로, 사실 나는 초보자로 데이터 과학을 접하면서 허탈하다는 생각이 종종 듭니다. 그렇게 데이터 수집과 전처리 과정을 거쳐 내놓은 결과물이 고작 차트와 같은 시각화 자료입니다. 물론 데이터 과학에서 시각화는 일부분이고, 무엇보다 시각화된 자료에서 유의미한 상관관계를 찾아 사용자의 의사결정에 도움이 된다면 그 역할을 다한 셈이죠. 하지만, 개인적으로 짧은 프로젝트를 하면서 내가 데이터 과학이 정말 하고싶은지에 대해 다시 고민하게 된 것 같습니다.