프로그래밍/Python

[Python] 4. 업비트 자동매매 프로그램 만들기 - 코드 합치기

록스타★ 2025. 1. 13. 22:03
반응형

이번 포스팅에서는 기존에 나누어 작성했던 업비트 연동 및 주문 관련 코드를 하나로 합쳐보고, 함수별로 어떻게 재활용할 수 있는지 살펴보겠습니다. 최종적으로는 불안정한 API 호출을 보완하기 위해 재시도(재요청) 로직을 포함한 fetch_data() 함수를 추가하여 전체적인 안정성을 높여보겠습니다.


주요 기능 설명

본격적으로 코드 합치기에 앞서, 코드를 간단히 정리해보겠습니다.

1. 업비트 연동
- access_key, secret_key를 활용하여 업비트 객체 생성
- 잔고 조회, 주문(매수/매도), 주문 조회 등 

2. 주요 함수
- fetch_data() : 네트워크 혹은 서버 이슈로 인해 데이터가 None으로 반환될 경우, 지정된 횟수만큼 재시도 하는 함수
- get_cur_price() : 현재가 조회
- get_balance_cash() : 보유 원화 조회
- get_balance_coin() : 보유 코인 수량 조회
- get_buy_avg() : 코인 매수 평균가 조회
- get_order_info() : 주문 상세 정보 조회 (주문 내역)
- order_buy_market() : 시장가 매수
- order_sell_market() : 시장가 매도
- order_buy_limit() : 지정가 매수
- order_sell_limit() : 지정가 매도
- order_cancel() : 진행 중인 주문 취소


코드 전체 합치기

- 꾸준히 말씀드리지만 pip install pyupbit가 되어 있어야 하며, access_key와 secret_key를 준비해둬야 합니다.
- 코드 제일 하단에 테스트 주문이 있는데, order_buy_market, order_sell_market 등 주문 함수를 사용 시 실제로 거래가 발생하니, 처음 테스트 할 때에는 소액으로 진행하시길 바랍니다.

import pyupbit
import requests
import time  # 필요 시 사용 (재시도, 딜레이 등)

# =========================================
# 1. Upbit API 키 정보 읽기
# -----------------------------------------
#  - ApiKey.txt (또는 key.txt)에 다음과 같은 형태로 저장:
#       첫째 줄: Access Key
#       둘째 줄: Secret Key
with open("ApiKey.txt", "r") as f:
    access_key = f.readline().strip()
    secret_key = f.readline().strip()

# =========================================
# 2. Upbit 인스턴스 생성
upbit = pyupbit.Upbit(access_key, secret_key)

# =========================================
# 3. 사용할 코인 티커 지정
#    예) "KRW-BTC", "KRW-XRP", "KRW-ETH" 등
coin = "KRW-BTC"

# =========================================
# 4. 조회용 함수들
def get_balance_cash():
    """
    보유 원화(KRW) 조회
    """
    return upbit.get_balance("KRW")

def get_cur_price(ticker):
    """
    특정 코인 현재 시세 조회
    """
    return pyupbit.get_current_price(ticker)

def get_balance_coin(ticker):
    """
    특정 코인 보유 수량 조회
    """
    return upbit.get_balance(ticker)

def get_buy_avg(ticker):
    """
    특정 코인의 평균 매수 단가 조회
    """
    return upbit.get_avg_buy_price(ticker)

def get_order_info(ticker_or_uuid):
    """
    특정 티커(KRW-XXX) 또는 주문 UUID에 대한
    미체결 주문 정보를 조회한다.
    (최근 주문부터 [0], 가장 마지막 주문은 [-1])
    """
    try:
        orders = upbit.get_order(ticker_or_uuid)
        if orders and "error" in orders[0]:
            return None
        return orders[-1] if orders else None
    except Exception as e:
        print("[get_order_info] 에러:", e)
        return None

def get_ticker_list():
    """
    업비트 전체 마켓 정보 조회 후,
    KRW-마켓만 추려서 {한글이름: 티커} 형태로 리턴
    예: {'비트코인': 'KRW-BTC', '리플': 'KRW-XRP', ...}
    """
    url = "https://api.upbit.com/v1/market/all"
    res = requests.get(url).json()
    ticker_dict = {}
    for item in res:
        market = item["market"]
        if market.startswith("KRW-"):
            kr_name = item["korean_name"]
            ticker_dict[kr_name] = market
    return ticker_dict

def get_open_orders(ticker: str = ""):
    """
    :param ticker: 코인 티커 (예: "KRW-BTC")
                  없으면 전체 미체결 주문 조회
    :return: 미체결 주문 목록(list)
    """
    try:
        orders = upbit.get_order(ticker)
        return orders
    except Exception as e:
        print("[get_open_orders] 에러:", e)
        return []

# (옵션) OHLCV 조회 함수 - 최근 일자별 시가/고가/저가/종가/거래량
def get_ohlcv_data(ticker, count=7):
    """
    지정된 count(일)만큼의 OHLCV(시가/고가/저가/종가/거래량) 정보를 DataFrame으로 반환
    """
    return pyupbit.get_ohlcv(ticker, count=count)

# =========================================
# 5. 주문 관련 함수들 (시장가 / 지정가 / 주문취소)
def order_buy_market(ticker: str, buy_amount: float):
    """
    시장가 매수
    :param ticker: 코인 티커 (예: "KRW-BTC")
    :param buy_amount: 매수 금액 (KRW 기준, 예: 10000.0)
    """
    if buy_amount < 5000:
        print("[order_buy_market] 최소 매수 금액은 5000원 이상 권장합니다.")
        return None

    try:
        print(f"[order_buy_market] {ticker} 시장가 매수 요청 - 금액: {buy_amount}")
        res = upbit.buy_market_order(ticker, buy_amount)
        
        if not res or 'error' in res:
            print("[order_buy_market] 매수 주문 실패:", res)
            return None
        
        print("[order_buy_market] 매수 주문 성공:", res)
        return res
    except Exception as e:
        print("[order_buy_market] 에러 발생:", e)
        return None

def order_sell_market(ticker: str, volume: float):
    """
    시장가 매도
    :param ticker: 코인 티커 (예: "KRW-BTC")
    :param volume: 매도할 코인 수량
    """
    try:
        print(f"[order_sell_market] {ticker} 시장가 매도 요청 - 수량: {volume}")
        res = upbit.sell_market_order(ticker, volume)
        
        if not res or 'error' in res:
            print("[order_sell_market] 매도 주문 실패:", res)
            return None
        
        print("[order_sell_market] 매도 주문 성공:", res)
        return res
    except Exception as e:
        print("[order_sell_market] 에러 발생:", e)
        return None

def order_buy_limit(ticker: str, price: float, volume: float):
    """
    지정가 매수
    :param ticker: 코인 티커 (예: "KRW-BTC")
    :param price: 매수 희망 가격
    :param volume: 매수할 수량
    """
    try:
        print(f"[order_buy_limit] {ticker} 지정가 매수 요청 - 가격: {price}, 수량: {volume}")
        res = upbit.buy_limit_order(ticker, price, volume)
        
        if not res or 'error' in res:
            print("[order_buy_limit] 지정가 매수 주문 실패:", res)
            return None
        
        print("[order_buy_limit] 지정가 매수 주문 성공:", res)
        return res
    except Exception as e:
        print("[order_buy_limit] 에러 발생:", e)
        return None

def order_sell_limit(ticker: str, price: float, volume: float):
    """
    지정가 매도
    :param ticker: 코인 티커 (예: "KRW-BTC")
    :param price: 매도 희망 가격
    :param volume: 매도할 수량
    """
    try:
        print(f"[order_sell_limit] {ticker} 지정가 매도 요청 - 가격: {price}, 수량: {volume}")
        res = upbit.sell_limit_order(ticker, price, volume)
        
        if not res or 'error' in res:
            print("[order_sell_limit] 지정가 매도 주문 실패:", res)
            return None
        
        print("[order_sell_limit] 지정가 매도 주문 성공:", res)
        return res
    except Exception as e:
        print("[order_sell_limit] 에러 발생:", e)
        return None

def order_cancel(uuid_val: str):
    """
    미체결 상태의 주문(wait)만 취소 가능
    :param uuid_val: 주문 시 반환되는 uuid 문자열
    """
    try:
        print(f"[order_cancel] 주문 취소 요청 - UUID: {uuid_val}")
        res = upbit.cancel_order(uuid_val)
        
        if not res or 'error' in res:
            print("[order_cancel] 주문 취소 실패:", res)
            return None
        
        print("[order_cancel] 주문 취소 성공:", res)
        return res
    except Exception as e:
        print("[order_cancel] 에러 발생:", e)
        return None

# =========================================
# 6. 메인 실행부 (직접 테스트할 때 사용)
if __name__ == "__main__":
    # -- 기본 조회 예시 --
    print("보유 KRW:", get_balance_cash())
    print(f"{coin} 현재 시세:", get_cur_price(coin))
    print(f"{coin} 보유 수량:", get_balance_coin(coin))
    print(f"{coin} 매수평단가:", get_buy_avg(coin))
    print(f"{coin} 최근 미체결 주문 정보:", get_order_info(coin))

    # -- 전체 KRW-마켓 티커 조회 예시 --
    all_tickers = get_ticker_list()
    print(f"\n전체 KRW-마켓 코인 개수: {len(all_tickers)}")
    if '리플' in all_tickers:
        print("리플의 티커:", all_tickers['리플'])

    # -- 원화마켓 목록 간단 조회 (중복 방법) --
    # (실제 코드 중복은 제거했지만 참고용)
    resp = requests.get("https://api.upbit.com/v1/market/all")
    data = resp.json()
    krw_tickers = [c['market'] for c in data if c['market'].startswith("KRW")]
    print("\nKRW-마켓 티커 리스트:", krw_tickers)

    # -- OHLCV 데이터 예시 (최근 7일)
    df = get_ohlcv_data("KRW-BTC", count=7)
    print("\n최근 7일 OHLCV:")
    print(df)

    # -- 주문 관련 함수 테스트 예시 (필요 시 주석 해제) --
    # 1) 시장가 매수 (예: 1만 원)
    #buy_result = order_buy_market(coin, 10000)

    # 2) 시장가 매도 (예: 0.001 BTC)
    #sell_result = order_sell_market(coin, 0.001)

    # 3) 지정가 매수 (예: BTC를 1,000만원에 0.001개 걸기)
    #limit_buy_result = order_buy_limit(coin, 10000000, 0.001)

    # 4) 지정가 매도 (예: BTC를 5,000만원에 0.001개 걸기)
    #limit_sell_result = order_sell_limit(coin, 50000000, 0.001)

    # 5) 미체결 주문 목록 조회 후 취소
    #open_orders = get_open_orders(coin)
    #if open_orders:
    #    print("\n미체결 주문 목록:", open_orders)
    #    recent_uuid = open_orders[0]['uuid']
    #    cancel_result = order_cancel(recent_uuid)

 


참조한 분과 코드의 맥락은 비슷하나 조금 다른 부분이 있을 수 있습니다. 그리고 참조한 분이 아주 상세히 잘 알려주셔서 방문 해보시는 걸 추천드립니다.

참조
https://mcc96.tistory.com/32

 

(Python) 업비트 자동 매매 프로그램 만들기(4) - 중간 점검

Summary 이번 게시물에서는 지난 게시물에서 작성한 코드들을 하나로 모아 보도록 하겠습니다. 그전에 각 기능들을 함수로 구현했을 때 호출 실패시 대응 방법을 먼저 추가해보겠습니다. 1) fetch_da

mcc96.tistory.com

 

반응형