최근 SNL 코리아에서 주현영 기자가 이준석 당내 대표를 취재하는 장면이 있었는데 이준석은 코인 자동매매를 돌리고 있다고 했다. 그것도 대선 3~4번 나갈 금액을 수익화했다고 전했다.
그 말을 듣고 나는 갑자기 궁금해졌다. 구글링 해서 제일 쉬운 자동매매 프로그램을 만들어보았다.
우선 세계 3대 비트코인 선물 거래소인 Bybit을 이용해서 프로그램을 짤 것이기 때문에 Bybit에서 제공하는 API를 만들자! 가입은 필수다!
Bybit API 만들기!
로그인을 하고 계정 모양을 누르면 API링크로 들어갈 수 있다.
그리고 Create New Key를 눌러 Key를 만들어주자!
위와 같은 화면이 나오는데 이제부터는 하나씩 자세히 알아보자.
<API Key Usage> API Transaction : 직접 사용할 것이기 때문에 이것을 사용할 것이다. Connect to Third-Party Applications : 다른 프로그램에서 연결해서 사용할 때 사용. Name : 별칭 같은건데 아무거나 입력해주면 된다. |
<API Key permissions (check all that apply)> Read-Write : RW속성, 읽고 쓰기 둘 다 하겠다. 이것을 써야 사고 팔 수 있다. Read-Only : 읽기만 하겠다. 그냥 정보만 들고 오겠다. Contract : 선물 사고 파는 것에 관여 (Position, 주문) SPOT : 현물 사고 파는 것에 관여 (주문) Wallet : 지갑 관리 (출금, 계정 내 이동, 코인 환전) |
<IP Access to API Keys> All IPs : 모든 IP에 대해 접근 시킨다. (단, 3개월 뒤 이 Key는 소멸된다.) Specified IPs only : 특정 IP로만 접근시킨다. (보안에 강함) |
빨간색 표시를 해놓은 부분은 선택한 부분이다.
API key permissions 부분은 다 체크를 해주긴 했다. 하지만 당장은 SPOT(현물) 주문과 Wallet(지갑) 관리는 안할거라서 체크를 하지 않아도 무방하다.
그 후 IP Access to API Keys 부분의 Specified IPs only에 프로그램을 돌릴 IP주소를 입력해준다.
(CMD 했을 때 IP말고 공인 IP를 적어줘야 하는데 https://myip.com 에 접속하면 볼 수 있다.)
다했으면 Submit을 눌러서 제출하자! 그러면 API Key와 API Secret을 얻을 수 있다.
여기서 주의! API Key와 API Secret을 반드시 복사해두자!
IP Addr 옆의 연필을 누르면 IP주소를 수정할 수 있다. API ID는 볼 수 있는 반면 Secret은 볼 수 없다.
그러니 API Secret을 반드시 복사해두자!
BYBIT GoldenCross/DeadCross 자동 매매의 위험 검증.
이전 글에서 Bybit API를 이용한 골든크로스/데드크로스 자동매매 프로그램을 구현했는데 그 프로그램에 대한 위험성 검증을 했다. Bybit API를 이용한 골드/데드 크로스 자동매매 프로그램. 최근 S
limetimeline.tistory.com
import pandas as pd
import datetime
import requests
import time
import calendar
from pybit import HTTP
from datetime import datetime, timedelta, timezone
from requests.api import post
apiKey = 'Input your API KEY'
apiSecret = 'Input your API Secret'
#symbol to be traded
symbol = 'MANAUSDT'
query_kilne = 'https://api.bybit.com/public/linear/kline?symbol=' # USDT
# query_kilne = 'https://api.bybit.com/v2/public/kline/list?symbol=' # USD
latest_infoSymbol = 'https://api.bybit.com/v2/public/tickers?symbol='
#candle in minutes
tick_interval = '1'
#quantity to be traded in USD
qty1 = 3
opt=0
while True:
bybitticker=symbol
now = datetime.utcnow()
unixtime = calendar.timegm(now.utctimetuple())
since = unixtime
start=str(since-60*60*int(tick_interval))
url = query_kilne+bybitticker+'&interval='+tick_interval+'&from='+str(start)
data = requests.get(url).json()
D = pd.DataFrame(data['result'])
marketprice = latest_infoSymbol + symbol
res = requests.get(marketprice)
data = res.json()
lastprice = float(data['result'][0]['last_price'])
price = lastprice
df = D['close']
ma9 = df.rolling(window=9).mean()
ma26 = df.rolling(window=26).mean()
test1=ma9.iloc[-2]-ma26.iloc[-2]
test2=ma9.iloc[-1]-ma26.iloc[-1]
session = HTTP(
endpoint = 'https://api.bybit.com/',
api_key=apiKey,
api_secret = apiSecret)
positionsize=session.my_position(symbol=symbol)['result'][0]['size']
if session.my_position(symbol=symbol)['result'][0]['side']=='Sell':
positionsize=positionsize*-1
lastprice = float(session.latest_information_for_symbol(symbol=symbol)['result'][0]['last_price'])
call='None'
try:
if test1>0 and test2<0:
if positionsize>0:
print('skip')
time.sleep(2)
continue
call = 'Dead Cross'
qty = qty1
if positionsize<0:
qty=qty1+abs(positionsize)
if opt == 0:
opt = 1
print(session.place_active_order(
symbol=bybitticker,
side='Buy',
order_type='Market',
qty=qty1,
time_in_force="GoodTillCancel",
reduce_only=False,
close_on_trigger=False
))
print(session.place_active_order(
symbol=bybitticker,
side='Buy',
order_type='Market',
qty=qty1,
time_in_force="GoodTillCancel",
reduce_only=True,
close_on_trigger=False
))
if test1<0 and test2>0:
if positionsize<0:
print('skip')
time.sleep(2)
continue
call='Golden Cross'
qty=qty1
if positionsize>0:
qty=qty1+abs(positionsize)
if opt == 1:
opt = 0
print(session.place_active_order(
symbol=bybitticker,
side='Sell',
order_type='Market',
qty=qty1,
time_in_force="GoodTillCancel",
reduce_only=True,
close_on_trigger=False
))
print(session.place_active_order(
symbol=bybitticker,
side='Sell',
order_type='Market',
qty=qty1,
time_in_force="GoodTillCancel",
reduce_only=False,
close_on_trigger=False
))
except:
pass
print('Name: ', bybitticker)
print('Date: ', now)
print('price: ', lastprice)
print('MA 9: ', round(ma9.iloc[-1],2))
print('MA 26: ', round(ma26.iloc[-1],2))
print('Golden Cross/Dead Cross: ', call)
print('opt: ', opt)
print('')
time.sleep(2)
위의 코드를 간략히 설명하자면...
목표 코인은 MANAUSDT (MANA, 디센트럴랜드)이고 한 번 주문할 때 마다 3개씩 시장가로 구매하도록 되어 있다.
첫 시도에서 Dead Cross일 때 Long 포지션을 주문하고 Golden Cross일 때 Long 포지션을 청산하고 Short 포지션을 주문한다. 그 후 Dead Cross가 왔을 때 Long 포지션을 주문하고 Short 포지션을 청산한다. (반복)
<Golden Cross / Dead Cross with MA 9, 26>Golden Cross는 MA(이동평균선) 9가 MA 26을 치고 올라갈 때를 말한다. Dead Cross는 MA(이동평균선) 26이 MA 9를 치고 올라갈 때를 말한다. |
처음에 나는 Golden Cross 이후로 오르고 Dead Cross 때 내려간다고 생각했는데 이게 정확하게 따라가지 않았다. 내가 무지했기 때문이기도 하지만 예측불가인 것이 당연했다. 코인은 더 위험하다.
이번 코드는 Golden Cross일 때, Dead Cross일 때의 두 조건에만 반응하는 프로그램이라 고쳐야할 부분은 크게 많지 않다. 가져다 쓸 경우 저 코드 그대로 쓰지 말고 적당히 고쳐서 쓰길 바란다. 저 코드는 완벽한 지표가 될 수 없다.
apiKey = 'Input your API KEY' # API Key를 입력하자! apiSecret = 'Input your API Secret' # API Secret을 입력하자! #symbol to be traded symbol = 'MANAUSDT' # 가지고 놀 코인이름을 입력하자! query_kilne = 'https://api.bybit.com/public/linear/kline?symbol=' # USDT # 코인 선물에서 USDT를 다룰 때 사용하는 API # query_kilne = 'https://api.bybit.com/v2/public/kline/list?symbol=' # USD # 코인 선물에서 USD를 다룰 때 사용하는 API #candle in minutes tick_interval = '1' # 몇 분 차트로 볼지 설정. 1은 1분 차트. |
<코인선물 USD와 USDT로 거래하는 API가 서로 다르다! 반드시 알맞게 고쳐야한다.> USD : BTCUSD나 MANAUSD 즉, USD로 거래하고 싶다. => symbol = 'BTCUSD' 또는 'MANAUSD' => query_kilne = 'https://api.bybit.com/v2/public/kline/list?symbol=' USDT : BTCUSDT나 MANAUSDT 즉, USDT로 거래하고 싶다. => symbol = 'BTCUSDT' 또는 'MANAUSDT' => query_kilne = 'https://api.bybit.com/public/linear/kline?symbol=' |
#quantity to be traded in USDT or USD qty1 = 3 # 한 번 거래할 때 마다 양. 코인마다 다르겠지? |
# MA(이동평균선) 9와 MA 26을 계산하는 작업. ma9 = df.rolling(window=9).mean() ma26 = df.rolling(window=26).mean() call = 'Dead Cross' # 데드크로스가 감지 되었을 때 여기로 들어와서 콘솔에 Dead Cross 출력 call = 'Golden Cross' # 골든크로스가 감지 되었을 때 여기로 들어와서 콘솔에 Golden Cross 출력 |
print(session.place_active_order( # 주문하기. symbol=bybitticker, # 주문할 코인 side='Buy', # Long주문 order_type='Market', # 시장가. qty=qty1, # 개수 time_in_force="GoodTillCancel", reduce_only=False, close_on_trigger=False )) print(session.place_active_order( # 주문하기. symbol=bybitticker, # 주문할 코인 side='Sell', # Long청산 order_type='Market', # 시장가. qty=qty1, # 개수 time_in_force="GoodTillCancel", reduce_only=True, close_on_trigger=False )) print(session.place_active_order( # 주문하기. symbol=bybitticker, # 주문할 코인 side='Sell', # Short주문 order_type='Market', # 시장가. qty=qty1, # 개수 time_in_force="GoodTillCancel", reduce_only=False, close_on_trigger=False )) print(session.place_active_order( # 주문하기. symbol=bybitticker, # 주문할 코인 side='Buy', # Short주문 order_type='Market', # 시장가. qty=qty1, # 개수 time_in_force="GoodTillCancel", reduce_only=True, close_on_trigger=False )) |
여기서 주의해야할 것은 주문할 때는 Buy(Long), Sell(Short) 그대로 적지만 청산할 경우 반드시 반대로 Buy(Short청산), Sell(Long청산)로 적어주고 reduce_only를 True로 해주어야 한다. |
추가로 지정가 매매의 경우 아래와 같이 해주면 된다. order_type과 price만 추가해주면 된다. 나머지는 위와 같다. |
print(session.place_active_order( symbol=bybitticker, side='포지션', qty=qty1, order_type='Limit', # 지정가 price=lastprice, # 가격인데 원하는 가격을 줘도되고 lastprice는 현재가격을 담고 있다. time_in_force="GoodTillCancel", reduce_only=False, close_on_trigger=False )) |
수정할 것은 이 정도? 만 하면 될 것 같다.
더 많은 API를 제공하고 있으니 더 자세한 API 정보는 https://bybit-exchange.github.io/docs/linear/#t-introduction 여기로 들어가보면 된다.
Bybit API Docs
bybit-exchange.github.io
궁금한 사항이 있다면 댓글을 남겨주십시오!
혹시나 코인 선물이나 위클리 옵션에 관심이 있다면 '안쌤TV'로 와서 함께 공부하는 것도 좋을 것 같다.
요즘 내가 도와드리고 있는 선생님이신데 내공이 상당하시다. 궁금한 것도 질문하면 잘 알려 주신다.
요즘 Youtube 방송도 저녁 10시부터 코인선물 방송을 하시고 오픈채팅도 운영하고 있으니 참고!
위클리옵션.국내선물/비트코인 - 안쌤... : 네이버 카페
주식/해외선물(홍콩항셍,나스닥,오일)/비트코인 등 실전 매매 전략과 철학을 배울 수 있는 공간입니다.
cafe.naver.com