혼자 만든 Code
UPBIT 코인 자동거래 프로그램 ver 1.0 (초 단위 캔들 매매)
빛하루
2024. 12. 10. 23:16
1초단위의 rsi 지표에서
rsi지수 23이하이면 폭락대비 1초 기다림 후 매수
rsi지수 30이하이면 매수1호가로 지정가 매수
rsi 지수 52이상이면 매도1호가로 지정가 매도
지정가 매도는 매도 실패시 계속 매도 1호가로 매도 시도
import requests
import jwt
import uuid
import json
from urllib.parse import urlencode
import pyupbit
import numpy as np
import pandas as pd
import hashlib
from urllib.parse import urlencode, unquote
import time
server_url = 'https://api.upbit.com'
# JSON 파일에서 API 키 불러오기
def load_api_keys(config_file="upbit_config.json"):
try:
with open(config_file, "r") as file:
keys = json.load(file)
return keys["api_key"], keys["secret_key"]
except Exception as e:
print(f"Error loading API keys: {e}")
return None, None
def get_upbit_account_info(api_key, secret_key):
base_url = "https://api.upbit.com/v1"
# JWT 토큰 생성
payload = {
'access_key': api_key,
'nonce': str(uuid.uuid4()),
}
jwt_token = jwt.encode(payload, secret_key, algorithm="HS256")
authorization_token = f"Bearer {jwt_token}"
headers = {
"Authorization": authorization_token,
}
# 계좌 조회 API 호출
try:
account_res = requests.get(f"{base_url}/accounts", headers=headers)
account_data = account_res.json()
if account_res.status_code != 200:
print(f"Error fetching account data: {account_data}")
return
# 코인별 정보 조회
market_data = requests.get(f"{base_url}/market/all").json()
market_dict = {item['market']: item['korean_name'] for item in market_data}
total_balance = 0
coin_info_list = []
for account in account_data:
if float(account['balance']) > 0: # 잔액이 0보다 클 경우
ticker = account['currency']
if ticker == "KRW":
total_balance += float(account['balance'])
continue
market = f"KRW-{ticker}"
avg_buy_price = float(account['avg_buy_price'])
balance = float(account['balance'])
# 현재 가격 조회
ticker_url = f"{base_url}/ticker?markets={market}"
ticker_res = requests.get(ticker_url).json()
current_price = float(ticker_res[0]['trade_price'])
# 평가 금액과 수익률 계산
eval_amount = balance * current_price
profit_rate = ((current_price - avg_buy_price) / avg_buy_price) * 100
# 총 자산에 반영
total_balance += eval_amount
coin_info_list.append({
"코인": market_dict.get(market, ticker),
"보유수량": balance,
"평균단가": avg_buy_price,
"현재가격": current_price,
"수익률": profit_rate,
})
# 출력
print(f"총 자산: {total_balance:,.0f} KRW")
print("보유 코인 정보:")
for coin in coin_info_list:
print(f"코인: {coin['코인']}, 보유수량: {coin['보유수량']}, "
f"평균단가: {coin['평균단가']}, 현재가격: {coin['현재가격']}, 수익률: {coin['수익률']:.2f}%")
except Exception as e:
print(f"An error occurred: {e}")
#coin의 candle 데이터를 가져오는 함수
def get_coin_data(coin):
url = "https://api.upbit.com/v1/candles/seconds"
params = {
'market': f'KRW-{coin}',
'count': 100,
}
headers = {"accept": "application/json"}
response = requests.get(url, params=params, headers=headers)
data = response.json()
df =pd.DataFrame(data)
df=df.reindex(index=df.index[::-1]).reset_index()
return df
#rsi를 계산하는 함수
def calculate_rsi(coin,period=14):
ohlc = get_coin_data(coin)
delta = ohlc["trade_price"].diff()
gains, declines = delta.copy(), delta.copy()
gains[gains < 0] = 0
declines[declines > 0] = 0
_gain = gains.ewm(com=(period-1), min_periods=period).mean()
_loss = declines.abs().ewm(com=(period-1), min_periods=period).mean()
RS = _gain / _loss
rsi = pd.Series(100-(100/(1+RS)), name="RSI")
last_rsi = float(rsi.iloc[-1])
return last_rsi
#보유하고 있는 코인 조회 함수
def get_coin_holdings(api_key, secret_key):
"""
업비트 API를 사용하여 보유 중인 코인의 종류와 수량을 가져옵니다.
Returns:
dict: 코인의 종류와 보유 수량을 포함한 딕셔너리
"""
base_url = "https://api.upbit.com/v1/accounts"
# JWT 토큰 생성
payload = {
'access_key': api_key,
'nonce': str(uuid.uuid4()),
}
jwt_token = jwt.encode(payload, secret_key, algorithm="HS256")
headers = {"Authorization": f"Bearer {jwt_token}"}
try:
# 계좌 정보 요청
response = requests.get(base_url, headers=headers)
response.raise_for_status()
accounts = response.json()
# 보유 코인 정보 필터링
holdings = {account['currency']: float(account['balance']) for account in accounts if float(account['balance']) > 0}
# 보유 코인이 없을 경우 처리
if not holdings:
print("보유 중인 코인이 없습니다.")
return {}
return holdings
except Exception as e:
print(f"Error fetching coin holdings: {e}")
return {}
# 미체결된 주문 조회
def check_unfilled_orders(api_key, secret_key):
"""
미체결 주문이 있는지 확인합니다.
Returns:
list: 미체결 주문 리스트 (없으면 빈 리스트)
"""
base_url = "https://api.upbit.com/v1/orders"
query = {
'state': 'wait', # 'wait' 상태는 미체결 주문을 의미
}
# Query Hash 계산
query_string = '&'.join([f"{key}={value}" for key, value in query.items()])
query_hash = hashlib.sha512(query_string.encode()).hexdigest()
# JWT 토큰 생성
payload = {
'access_key': api_key,
'nonce': str(uuid.uuid4()),
'query_hash': query_hash,
'query_hash_alg': 'SHA512',
}
jwt_token = jwt.encode(payload, secret_key, algorithm="HS256")
headers = {"Authorization": f"Bearer {jwt_token}"}
try:
# 미체결 주문 요청
response = requests.get(base_url, headers=headers, params=query)
response.raise_for_status()
orders = response.json()
# 미체결 주문이 없는 경우 처리
if not orders:
print("미체결 주문이 없습니다.")
return []
print("미체결 주문이 있습니다.")
return orders
except Exception as e:
print(f"Error fetching unfilled orders: {e}")
return []
#미체결된 주문 취소하는 함수
def cancel_unfilled_order(api_key, secret_key, order_id):
"""
특정 미체결 주문을 취소합니다.
Args:
api_key (str): 업비트 API 키
secret_key (str): 업비트 Secret 키
order_id (str): 취소할 주문의 UUID
Returns:
dict: 주문 취소 결과
"""
base_url = "https://api.upbit.com/v1/order"
query = {
'uuid': order_id,
}
# JWT 토큰 생성
query_string = '&'.join([f"{key}={value}" for key, value in query.items()])
payload = {
'access_key': api_key,
'nonce': str(uuid.uuid4()),
'query_hash': hashlib.sha512(query_string.encode()).hexdigest(),
'query_hash_alg': 'SHA512',
}
jwt_token = jwt.encode(payload, secret_key, algorithm="HS256")
headers = {"Authorization": f"Bearer {jwt_token}"}
try:
# 주문 취소 요청
response = requests.delete(base_url, headers=headers, params=query)
response.raise_for_status()
cancel_result = response.json()
print(f"주문이 성공적으로 취소되었습니다: {cancel_result}")
return cancel_result
except requests.exceptions.HTTPError as e:
print(f"HTTP 에러 발생: {e.response.status_code}, {e.response.text}")
return {}
except Exception as e:
print(f"Error canceling order: {e}")
return {}
#매수 1호가와 매도1호가 리턴하는 함수
def get_orderbook(api_key, market="KRW-BTC"):
"""
주어진 마켓의 매수, 매도 1호가를 가져옵니다.
Args:
api_key (str): 업비트 API 키
market (str): 마켓 코드 (예: "KRW-BTC")
Returns:
dict: 매수 1호가와 매도 1호가를 포함한 딕셔너리
"""
url = f"https://api.upbit.com/v1/orderbook?markets={market}&level=0"
headers = {"accept": "application/json"}
try:
# 주문서 정보 요청
response = requests.get(url, headers=headers)
response.raise_for_status()
orderbook = response.json()
if not orderbook:
print(f"{market}의 주문서 정보가 없습니다.")
return None
# 매수 1호가 (가장 높은 매도 호가)
ask_price = orderbook[0]['orderbook_units'][0]['ask_price']
# 매도 1호가 (가장 낮은 매수 호가)
bid_price = orderbook[0]['orderbook_units'][0]['bid_price']
return {"bid_price": bid_price, "ask_price": ask_price}
except Exception as e:
print(f"Error fetching orderbook: {e}")
return None
#지정가 매수함수
def place_limit_buy_order(api_key, secret_key, market, price, budget):
max_quantity = str(budget / price)
params = {
'market': market,
'side': 'bid',
'ord_type': 'limit',
'price': price,
'volume': max_quantity
}
query_string = unquote(urlencode(params, doseq=True)).encode("utf-8")
m = hashlib.sha512()
m.update(query_string)
query_hash = m.hexdigest()
payload = {
'access_key': api_key,
'nonce': str(uuid.uuid4()),
'query_hash': query_hash,
'query_hash_alg': 'SHA512',
}
jwt_token = jwt.encode(payload, secret_key)
authorization = 'Bearer {}'.format(jwt_token)
headers = {
'Authorization': authorization,
}
res = requests.post(server_url + '/v1/orders', json=params, headers=headers)
order_result = res.json()
# 성공적으로 주문을 제출했다면 주문 UUID 반환
order_uuid = order_result.get('uuid')
if order_uuid:
print(f"매수 주문이 성공적으로 생성되었습니다. 주문 UUID: {order_uuid}")
time.sleep(3)
return order_uuid
else:
print("주문 생성 실패: UUID를 찾을 수 없습니다.")
return None
# 지정가 매도함수
def place_limit_sell_order(api_key, secret_key, market, price, quantity):
max_quantity = str(quantity)
params = {
'market': market,
'side': 'ask',
'ord_type': 'limit',
'price': price,
'volume': max_quantity
}
query_string = unquote(urlencode(params, doseq=True)).encode("utf-8")
m = hashlib.sha512()
m.update(query_string)
query_hash = m.hexdigest()
payload = {
'access_key': api_key,
'nonce': str(uuid.uuid4()),
'query_hash': query_hash,
'query_hash_alg': 'SHA512',
}
jwt_token = jwt.encode(payload, secret_key)
authorization = 'Bearer {}'.format(jwt_token)
headers = {
'Authorization': authorization,
}
res = requests.post(server_url + '/v1/orders', json=params, headers=headers)
order_result = res.json()
# 성공적으로 주문을 제출했다면 주문 UUID 반환
order_uuid = order_result.get('uuid')
if order_uuid:
print(f"매도 주문이 성공적으로 생성되었습니다. 주문 UUID: {order_uuid}")
time.sleep(3)
return order_uuid
else:
print("주문 생성 실패: UUID를 찾을 수 없습니다.")
return None
# 사용 방법
api_key, secret_key = load_api_keys("upbit_config.json")
if api_key and secret_key:
coin = input('코인 명 : ')
money = float(input('투입 금액 : '))
while True:
coin_holdings = get_coin_holdings(api_key, secret_key)
if len(coin_holdings)==1:
market = f'KRW-{coin}'
coin_rsi = calculate_rsi(coin,14)
if coin_rsi<=30 and coin_rsi>=23:
orderbook = get_orderbook(api_key, market)
buy_price = orderbook['bid_price']
buy_uuid = place_limit_buy_order(api_key,secret_key,market,buy_price,money)
unfilled_orders = check_unfilled_orders(api_key, secret_key)
if unfilled_orders:
print('지정가 매수 실패, 미체결 주문 취소 작업 중..')
for order in unfilled_orders:
cancel_result = cancel_unfilled_order(api_key, secret_key, buy_uuid)
# for order in unfilled_orders:
# print(f"주문 ID: {order['uuid']}, 코인: {order['market']}, 수량: {order['volume']}, 상태: {order['state']}")
get_upbit_account_info(api_key,secret_key)
elif coin_rsi <23:
print("폭락 대비 1초대기중..")
time.sleep(1)
orderbook = get_orderbook(api_key, market)
buy_price = orderbook['bid_price']
buy_uuid = place_limit_buy_order(api_key,secret_key,market,buy_price,money)
unfilled_orders = check_unfilled_orders(api_key, secret_key)
if unfilled_orders:
print('지정가 매수 실패, 미체결 주문 취소 작업 중..')
for order in unfilled_orders:
cancel_result = cancel_unfilled_order(api_key, secret_key, buy_uuid)
# for order in unfilled_orders:
# print(f"주문 ID: {order['uuid']}, 코인: {order['market']}, 수량: {order['volume']}, 상태: {order['state']}")
get_upbit_account_info(api_key,secret_key)
else:
print(f'현재 rsi 값이 30이상 입니다 - 현재 rsi 값 : {coin_rsi}')
print('')
get_upbit_account_info(api_key,secret_key)
print('')
else:
hold_coin = list(coin_holdings.keys())[1]
hold_coin_amount = float(coin_holdings[hold_coin])
market = f'KRW-{hold_coin}'
coin_rsi = calculate_rsi(hold_coin,14)
if coin_rsi>=52:
orderbook = get_orderbook(api_key, market)
market = f'KRW-{hold_coin}'
sell_uuid = place_limit_sell_order(api_key,secret_key,market,orderbook['ask_price'],hold_coin_amount)
while len(check_unfilled_orders(api_key,secret_key))>0:
cancel_result = cancel_unfilled_order(api_key,secret_key,sell_uuid)
get_upbit_account_info(api_key,secret_key)
else:
print(f'현재 rsi 값이 52이하 입니다. - 현재 rsi : {coin_rsi}')
print('')
get_upbit_account_info(api_key,secret_key)
print('')
# if coin_holdings:
# print("보유 코인 정보:")
# for coin, amount in coin_holdings.items():
# print(f"코인: {coin}, 보유 수량: {amount}")
# if unfilled_orders:
# for order in unfilled_orders:
# order_id = order['uuid'] # 취소하려는 주문 ID를 입력
# cancel_result = cancel_unfilled_order(api_key, secret_key, order_id)
# orderbook = get_orderbook(api_key, market)
# if orderbook:
# print(f"매수 1호가: {orderbook['bid_price']}, 매도 1호가: {orderbook['ask_price']}")
# order_uuid = place_limit_buy_order(api_key, secret_key, market, orderbook['bid_price'], money)
# if order_uuid:
# print(f"주문 UUID: {order_uuid}")
# else:
# print("주문을 생성할 수 없습니다.")