본문 바로가기

Projects/업무-무역

[텔레그램 봇] 하나은행 환율 매매기준율 알리미

구현 사례

하나은행 매매기준율 알리미 봇

Why? 왜 이걸 만들었는가

  • 회사 동기가 '이런 기능을 해주는 프로그램이 있었으면 좋겠다' 고 해서 만들어 보았다.
  • 본인은 환율을 유심히 들여다 보는 경우가 아니지만, 환율에 민감한 분들은 당일 하나은행의 1회,2회, 그리고 가장 마지막으로 업데이트된 매매기준율을 참고한다고 한다.
  • '그냥 최신 매매기준율만 참고하면 되는데 왜 1,2회를 참고하는지 물어보니, 실제 당일의 매매기준율 추이를  결정하는 매우 중요한 Factor가 1,2회 매매기준율이라고 한다. (역시 모든 심리는 첫 거래에 다 반영이 되나 보다)

 

프로젝트 개요

언어 : Python

주요 패키지(Framework) :

  • Python-Telegram-Bot - 대화형 로직을 쉽고 빠르게 짤 수 있는 툴이다 (Telegram API가 애초에 너무 좋긴 하다)
  • Pandas : 데이터 전처리 필터링 수행
  • Requests : 데이터 크롤링 

작동 방식 :

  1. 유저가 매매기준율을 알려달라고 메시지를 보낸다
  2. 그 시점에서 하나은행 환율 조회 사이트의 html table를 데이터프레임으로 가져온다
  3. Pandas 전처리를 이용해서 1회,2회 그리고 최신 매매기준율을 뽑아낸 후, 유저에게 회신한다.

서버 : Raspberry Pi4 background에서 계속 실행 (Long Polling) 

  • 컨테이너를 AWS Lambda 위에서 올려서 구현하는 방식도 가능 (단, 이 경우 Webhook 방식을 이용해야 함)

하나은행 환율 매매기준율 조회 (https://www.kebhana.com/cont/mall/mall15/mall1501/index.jsp)

 

구현 코드

import logging
import os
import pandas as pd
import requests
from telegram import Bot
from telegram.ext import Updater, CommandHandler
from get_ex import get_usd_ex
from datetime import datetime, timedelta

# Enable logging
# logging이 콘솔이랑 파일 형태로 모두 갈 수 있도록 설정 (with StreamHandler)
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO,
                    handlers=[
        logging.FileHandler(f"{os.path.splitext(os.path.basename(__file__))[0]}.log"),
        logging.StreamHandler()])

logger = logging.getLogger(__name__)

TOKEN = 'mybot_token'
URL = f"https://api.telegram.org/bot{TOKEN}/"


bot = Bot(token=TOKEN)



# 데이터를 가져오는 함수 
def get_usd_ex():


    url5 = 'https://www.kebhana.com/cms/rate/wpfxd651_07i_01.do'

    today_date = datetime.today().strftime('%Y%m%d')
    today_string = datetime.today().strftime('%Y-%m-%d')
    headers = {
    'User=Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36',
    'Content-type':'application/x-www-form-urlencoded; charset=UTF-8',
    'Accept':'text/javascript, text/html, application/xml, text/xml, */*',
    'Origin':'https://www.kebhana.com',
    'Host':'www.kebhana.com',
    'Referer':'https://www.kebhana.com/cms/rate/index.do?contentUrl=/cms/rate/wpfxd651_01i.do'}

    data = f'ajax=true&inqType=0&curCd=USD&tmpPbldDvCd=1&inqDt={today_date}&inqDvCd=1&requestTarget=searchContentDiv'

    response = requests.post(url=url5, headers=headers, data=data,allow_redirects=True)


    ## 2단계 pd.read_html를 통해서 특정 테이블을 df로 바로 가져오기

    df = pd.read_html(response.text)[0]

    df.columns = ['회차', '시간', '현찰_살때','현찰_팔때','송금_보낼때','송금_받을때','T/C','외화','매매기준율','직전대비','환가료율','미화환산율']
    df = df[['회차','시간','매매기준율']]


    first_value = df.loc[df['회차']== 1,'매매기준율'].values[0]
    second_value = df.loc[df['회차']== 2,'매매기준율'].values[0]
    last_value = df.loc[df['회차'] == df['회차'].max(),'매매기준율'].values[0]
    last_num = df['회차'].max()
    mylist = [first_value, second_value, last_value]
    mymessage = f"기준일 : {today_string} 외화 : USD \n {mylist[0]} (1회) \n {mylist[1]} (2회) \n {mylist[2]} ({last_num}회, 최종)"
    return mymessage


## 유저가 명령어를 입력하면 동작하는 함수 정의

def start(update, context):
    text = "하나은행 환율 매매기준율 알리미 봇입니다. \n최근 매매기준율을 확인하려면 /fx를 입력해 주세요 \n기타 문의사항은 /admin 로 전달해주세요."
    update.message.reply_text(text)

def get_hana(update, context):
    mymessage = get_usd_ex()
    update.message.reply_text(mymessage)


## 에러는 일괄 처리
def error(update, context):
    """Log Errors caused by Updates."""
    logger.warning('Update "%s" caused error "%s"', update, context.error)


def main():
    """Start the bot."""

    updater = Updater(TOKEN, use_context=True)

## 유저 Command와 함수의 연결
    # Get the dispatcher to register handlers
    dp = updater.dispatcher
    dp.add_handler(CommandHandler("start", start))
    dp.add_handler(CommandHandler("fx", get_hana, pass_args=True))
    dp.add_error_handler(error)

    updater.start_polling()
    updater.idle()



if __name__ == '__main__':
    main()

Comments

  1. 텔레그램 api에서 제공하는 date는 Unix Timestamp 형태인데, 한국 시간으로 바꿔주려면 9시간을 더해줘야 한다. 
  2. 텔레그램 봇에 부여된 명령어를 사용하려면 빗금?(slash, /)를 쳐야 하는데, 유저 입장에서는 조금 불편하다. 다행히BotFather에서 Command List를 설정하면 유저 화면에 [/] 아이콘이 떠서 클릭만으로 명령어를 실행할 수 있다
    • Command List 설정법 : BotFather와 대화 → /setcommands → 봇 선택 → command 입력
  3. Pandas의 read_html 정말 매우 강력한 툴이다. Requests 라이브러리와 적절히 결합하면 대부분의 데이터를 read_html로  효율적으로 가져올 수 있다.