ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [업비트] 매주 평단 체크, 평단보다 시세가 낮으면 매수
    Python/파이썬과 주식 2025. 3. 9. 20:04
    반응형

    자동 매매 프로그램을 만들기 위해 많은 로직들을 테스트해 보았다. 

    특정 상황에서 유리한 로직은 꽤 만들었지만...
    제너럴한 상황에선 이렇게 단순한 로직을 이기는 게 쉽지 않았다.
    물론 본인의 실력 탓이리라...

    어찌 되었건 
    심플 이즈 베스트..

    pip install schedule
    pip install pyupbit

    원래 빗썸을 사용했는데, 빗썸에서는 평단을 체크하기 쉽지 않았다.
    거래소를 옮기는 게 제일 편한 해결책...

    두나무는 카카오 계열이라 API 관리가 구리진 않다는 이야길 듣고 바로 옮김.  

    from configparser import ConfigParser
    from datetime import datetime
    from time import sleep
    
    import pyupbit
    import schedule
    
    TICKER = 'KRW-BTC'
    BUY_AMOUNT = 50_000  # 매수 금액이 5000원 이상이어야 합니다.
    
    config = ConfigParser()
    config.read('upbit.ini')
    access_key = config['keys']['acc_key']
    secret_key = config['keys']['sec_key']
    
    upbit = pyupbit.Upbit(access_key, secret_key)
    
    
    def retry(func, max_retries=20, delay=0.5):
        retries, res = 0, None
        while res is None and retries < max_retries:
            res = func()
            sleep(delay)
            retries += 1
        if retries == max_retries:
            raise '재시도 설정 이상으로 재시도 됨.'
        return res
    
    
    def get_avg_buy_price(ticker):
        return retry(lambda: upbit.get_avg_buy_price(ticker))
    
    
    def get_current_price(ticker):
        return retry(lambda: pyupbit.get_current_price(ticker))
    
    
    def get_balances():
        return retry(lambda: upbit.get_balances())
    
    
    def get_balance(ticker):
        return retry(lambda: upbit.get_balance(ticker))
    
    
    def buy_market_order(ticker, buy_amount):
        try:
            res = upbit.buy_market_order(ticker, buy_amount)
            print(res)
        except Exception as e:
            print(e)
    
    
    def check_balance():
        krw_balance = get_balance('KRW')
        if krw_balance < BUY_AMOUNT:
            print(f'KRW: {krw_balance}, KRW가 설정된 구입금액보다 부족합니다.')
    
    
    def main():
        btc_price = get_current_price(TICKER)
    
        # 원화 잔고
        krw_balance = get_balance('KRW')
    
        # 비트코인 잔고
        btc_balance = get_balance(TICKER)
    
        # 평균 매수가 조회
        avg_buy_price = get_avg_buy_price(TICKER)
    
        print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
        print(f'{TICKER} 가격: {btc_price:,}\n'
              f'{TICKER} 평균매수가: {avg_buy_price:,}\n'
              f'{TICKER} 잔고: {btc_balance}\n'
              f'KRW 잔고: {krw_balance:,}')
        buy_market_order(TICKER, BUY_AMOUNT)
        if avg_buy_price > btc_price:
            print(f'현재 {TICKER} 가격보다 평균매수가가 높아 구매가 필요합니다.')
            if krw_balance >= BUY_AMOUNT:
                buy_market_order(TICKER, BUY_AMOUNT)
            else:
                print(f'계좌내 KRW 잔고가 {krw_balance:,}으로 '
                      f'{BUY_AMOUNT}보다 작아 매수를 진행할 수 없습니다.')
        else:
            print(f'현재 {TICKER} 가격보다 평균매수가가 낮습니다.')
    
    
    if __name__ == '__main__':
        schedule.every().saturday.at("19:35").do(check_balance)
        schedule.every().sunday.at("19:35").do(main)
        while True:
            schedule.run_pending()
            sleep(1)

    굳이 함수를 한 번씩 다시 작성한 이유는 다른 거래소를 사용하더라도 최소한의 수정을 하기 위해서 인데...
    업비트만 쓸 것이라면 굳이 저렇게 작성할 필요는 없을 것 같다. 

    upbit.ini

    [keys]
    acc_key=*************************
    sec_key=*************************

    핵심만 간단하게 코딩한 지라..
    추가해야 할 기능이 많은데...
    그중 슬랙이나 텔레그램으로 메시지를 보내주는 기능이 특히 필요해 보인다. 
    특히 잔액 부족이나, 거래 결과를 전송하는 기능이 필요한 것 같다.

     

    [백테스트를 해보자]

    대략 2021년 11월 8일 전후가 전고점이었으므로 이때를 시작점으로 위 방법으로 거래시 종가와 평단가를 비교해보자.  

    당연한 이야기지만 압도적인 퍼포먼스를 보여준다. 
    (하지만 물을 타고 타고 또 탔는데도 반토막도 안되는 구간이 보이는 게 함정)
    1회차 11월 8일 입금 후 입금일은 다음과 같고 총 67회, 335만원이다.

    2 2021-11-27
    3 2021-12-04
    4 2021-12-11
    5 2021-12-18
    6 2021-12-25
    7 2022-01-01
    8 2022-01-08
    9 2022-01-15
    10 2022-01-22
    11 2022-01-29
    12 2022-02-05
    13 2022-02-12
    14 2022-02-19
    15 2022-02-26
    16 2022-03-05
    17 2022-03-12
    18 2022-03-19
    19 2022-03-26
    20 2022-04-23
    21 2022-04-30
    22 2022-05-07
    23 2022-05-14
    24 2022-05-21
    25 2022-05-28
    26 2022-06-04
    27 2022-06-11
    28 2022-06-18
    29 2022-06-25
    30 2022-07-02
    31 2022-07-09
    32 2022-07-16
    33 2022-07-23
    34 2022-07-30
    35 2022-08-06
    36 2022-08-13
    37 2022-08-20
    38 2022-08-27
    39 2022-09-03
    40 2022-09-10
    41 2022-09-17
    42 2022-09-24
    43 2022-10-01
    44 2022-10-08
    45 2022-10-15
    46 2022-10-22
    47 2022-10-29
    48 2022-11-05
    49 2022-11-12
    50 2022-11-19
    51 2022-11-26
    52 2022-12-03
    53 2022-12-10
    54 2022-12-17
    55 2022-12-24
    56 2022-12-31
    57 2023-01-07
    58 2023-01-14
    59 2023-01-21
    60 2023-01-28
    61 2023-02-04
    62 2023-02-11
    63 2023-02-18
    64 2023-02-25
    65 2023-03-04
    66 2023-03-11
    67 2023-03-18

    최종적으로는 최고점을 넘겨서 살짝 떨어진 결과 = 12,727,580원. 

    반응형
Designed by Tistory.