프로그래밍/파이썬

[Python] 국내 ETF 저가 알림 봇 만들기

퀀트매니아 2023. 2. 11. 22:38
728x90

Python - 국내 ETF 저가 알림 봇 만들기

 

안녕하세요.

오늘은 파이썬과 텔레그램을 이용하여 국내 ETF 저가 알림 봇을 만들어보려고 합니다.

 

국내 ETF에 투자를 하고 있던 중, 특정 이동평균 이하로 가격이 내려갔을 때 알람을 받아보고 싶어 이 ETF 알림 봇을 만들어보게 되었는데요.

 

네이버 금융 사이트에서 데이터를 스크래핑해서 사용하는 방식이며, 제가 작성한 코드에서 원하시는 ETF 종목 코드만 바꾸신다면, 해당 ETF 종목의 알림이 텔레그램 채팅방에 발송되도록 하여 유용하게 활용하실 수 있을 것 같아 이번시간에 해당 방법을 소개해드리려고 합니다.

 

 

네이버 금융 ETF 설명

 

 

▼ 혹시, 아직 텔레그램 봇을 생성하지 않으셨다면, 아래 링크를 이용하여 생성 방법을 확인하실 수 있습니다.

[Python] 텔레그램을 이용하여 챗봇 만들기

 

[Python] 텔레그램을 이용하여 챗봇 만들기

텔레그램을 이용하여 챗봇 만들기 안녕하세요. 오늘은 텔레그램을 이용하여 챗봇을 만들어보는 시간을 가져보도록 하겠습니다. 1. 챗봇 생성하기 먼저, 텔레그램 어플을 받으신 뒤 검색창에 Bot

quantmania.tistory.com

 

 

 

필요 라이브러리

 

이번에 작성할 파이썬 코드에 필요한 라이브러리를 아래 pip 명령어로 제공해 드릴 테니 복사하셔서 설치를 진행하시면 되겠습니다.

 

pip install datetime
pip install pandas
pip install requests
pip install json
pip install python-telegram-bot
pip install time
pip install asyncio

 

 

 

전체코드

 

아래 코드는 30분 간격으로 국내 주식시장 개장 시간 동안 알림 받을 ETF의 가격이 특정 이동평균 아래로 떨어지면 알림을 보내주는 알림 봇을 구동하는 코드입니다.

 

from datetime import datetime
import pandas as pd
import requests
import json
import telegram
import time
import asyncio


# 텔레그램 정보
s_token = '텔레그램 토큰 입력'
l_chat_id = 채팅ID 입력
bot = telegram.Bot(s_token)


def get_etf_price(code):
    """ 현재가, 등락률 구하는 함수 """

    # 네이버 ETF URL
    url = 'https://finance.naver.com/api/sise/etfItemList.nhn'

    json_data = json.loads(requests.get(url).text)
    df_etf_list = pd.json_normalize(json_data['result']['etfItemList'])

    df_etf_list = df_etf_list.set_index('itemcode')

    itemname = df_etf_list.loc[code].loc['itemname']
    nowVal = df_etf_list.loc[code].loc['nowVal']
    changeVal = df_etf_list.loc[code].loc['changeVal']
    changeRate = df_etf_list.loc[code].loc['changeRate']

    return itemname, nowVal, changeVal, changeRate

def get_moving_average(code):
    """ 이동평균을 구하고 채팅방으로 메시지 전송 """

    time_now = datetime.now()
    str_today = time_now.strftime('%Y.%m.%d')

    # 네이버 일별시세
    df = pd.DataFrame()
    sise_url = 'https://finance.naver.com/item/sise_day.nhn?code=' + code

    for page in range(1, 8):
        page_url = '{}&page={}'.format(sise_url, page)
        response_page = requests.get(page_url, headers={'User-agent': 'Mozilla/5.0'}).text
        df = df.append(pd.read_html(response_page)[0])

    df = df.dropna() # n/a 제거
    df = df.reset_index(drop=True) # 인덱스 리셋
    df = df.rename(index=df['날짜'])

    if str_today == str(df.iloc[0].name):
        lastday = df.iloc[1].name
    else:
        lastday = df.iloc[0].name

    closes = df['종가'].sort_index()   
    ma_20 = closes.rolling(window=20).mean() # 20일 이동평균
    ma_60 = closes.rolling(window=60).mean() # 60일 이동평균

    ret_20 = round(ma_20.loc[lastday])
    ret_60 = round(ma_60.loc[lastday])

    code_name, cur_price, chan_val, chan_rate = get_etf_price(code)

    total_msg = ""
    if cur_price < ret_20 and cur_price < ret_60: # 이동평균보다 저가인 경우
        total_msg = total_msg + "[" + code_name + "] \n※ 20일 이동평균 : " + str(ret_20) + "원"
        total_msg = total_msg + "\n※ 60일 이동평균 : " + str(ret_60) + "원"
        total_msg = total_msg + "\n※ 현재가 : " + str(cur_price) + "원"
        if chan_val > 0:
            chan_symbol = " ▲ "
        elif chan_val == 0:
            chan_symbol = " - "
        else:
            chan_symbol = " ▼ "

        total_msg = total_msg + chan_symbol + str(chan_val) + " (" + str(chan_rate) + "%)"

		# 메시지 전송
        asyncio.run(bot.send_message(text=total_msg, chat_id=l_chat_id))

if __name__ == '__main__':

    # 알림받을 ETF 지정
    etf_list = ['069500']

    while True:
        # 현재시간 저장
        t_now = datetime.now()

        # 알림 시간 지정
        t_9 = t_now.replace(hour=8, minute=56, second=0, microsecond=0)
        t_exit = t_now.replace(hour=15, minute=34, second=0,microsecond=0)

        # 오늘의 요일 저장
        today = datetime.today().weekday()
        
        if today != 5 and today != 6:  # 토요일이나 일요일 제외
            if t_9 < t_now < t_exit:
                if (t_now.minute % 30 == 0 and 0 <= t_now.second <= 11): # 30분 마다 체크하도록 설정
                    for sym in etf_list:
                        get_moving_average(sym)
                        time.sleep(1)
                    time.sleep(65) # 중복 실행 방지

 

위 코드를 실행해 봤더니, 장중에 30분 단위로 ETF의 저가 알림이 잘 오는 것을 확인할 수 있었습니다.

 

 

ETF 알림 내역

 

 

 

코드 설명

 

다음으로 코드에 대해 설명을 드리도록 하겠습니다. 먼저, 메인 부분을 살펴보도록 하겠습니다.

 

 

코드 설명 1 - 메인

 

 

  • etf_list 변수에 알림을 받기 원하시는 ETF의 종목 코드를 넣으시면 되는데요. 종목코드는 네이버 금융 사이트에서 ETF를 검색하시면 ETF의 명칭 오른쪽에 종목코드가 표시되어 있습니다. 이 코드를 etf_list에 지정해 주시면 됩니다.

 

 

ETF 검색

 

코드 추가 예시

 

 

  • t_9 변수에는 시작 시간을, t_exit 변수에는 종료시간을 넣어서 알림 시간을 지정했습니다.
  • t_now는 현재 시간인데요, 이 시간이 30분으로 나누어 떨어지면, 즉, 30분 단위로 알림을 보내도록 설정했습니다. 이 부분은 원하시는 간격을 지정하시면 되겠습니다.

 

 

다음은 이동평균을 구하고, 채팅방으로 저가 알림 메시지를 보내는 get_moving_average 함수를 살펴보겠습니다.

 

 

코드 설명 2 - get_moving_average 함수

 

 

  • 코드에 네이버 일별시세라고 되어있는 부분을 보시면, 네이버의 ETF 일별 시세페이지에서 데이터를 스크래핑하여 이동평균을 구하는 방식으로 코드를 구성한 것을 보실 수 있는데요. 여기서 window 부분을 늘리고 줄이셔서 이동평균 일수를 정하실 수 있습니다.
  • 예를 들어, 더 긴 기간인 200일 이동평균을 사용하신다면, page 부분의 range를 늘려서 200일 정도의 데이터가 나오게 만들고, 실제 계산하는 부분인 window 지정 부분에서 200일로 변경하시면 되겠습니다. (sise_url의 주소로 실제 접속해 본 아래 사진의 일별시세를 참고하시면 이해가 되실 것 같습니다.)

 

 

네이버 금융 일별시세

 

 

끝으로, get_etf_price 함수에 대한 설명을 드리도록 하겠습니다.

 

 

코드 설명 3 - get_etf_price

 

 

  • 네이버 금융 ETF API 페이지를 접속해서 ETF의 이름과 현재가 그리고, 등락률 등을 가져오는 함수입니다.

 

 

네이버 금융 ETF API 페이지

 

 

 

마무리...

 

오늘은 파이썬과 텔레그램을 이용하여 국내 ETF 저가 알림 봇을 만드는 방법에 대해 소개해드렸습니다.

다음 포스팅에서도 유용한 정보를 소개하는 시간으로 찾아뵙도록 하겠습니다. 감사합니다!

 

728x90