본문 바로가기
자기개발/코딩, 데이터분석

[코딩 프로젝트] Python으로 주가 변동성 모니터링 및 WhatsApp 뉴스 알림 봇 만들기

by 공부하는노아 2025. 11. 9.

Python으로 주가 변동성 모니터링 및 WhatsApp 뉴스 알림 봇 만들기

투자자라면 누구나 관심 있는 종목의 주가 변동성에 민감할 것입니다. 하지만 매번 HTS나 MTS에 접속해 주가를 확인하고 관련 뉴스를 검색하는 것은 꽤 번거로운 일입니다.

 

이 프로젝트는 이러한 반복 작업을 자동화하기 위해 시작되었습니다. 특정 주식(예: Tesla)의 일일 주가 변동률이 설정한 임계값(예: 3%)을 초과할 경우, 관련 최신 뉴스를 요약하여 제 WhatsApp으로 자동으로 보내주는 파이썬 스크립트를 개발했습니다.

 

최종 결과물

프로젝트 목적

  1. 시간 절약: 주가와 뉴스를 수동으로 확인하는 시간을 줄입니다.
  2. 신속한 정보 습득: 시장의 큰 변동성을 즉각적으로 파악하고 관련 배경 뉴스를 빠르게 수신합니다.
  3. 자동화 구현: API 연동 및 메시징 서비스 자동화에 대한 실습을 진행합니다.

사용된 기술 스택

  • Python 3.11
  • 라이브러리:
    • requests: HTTP 요청을 보내 API 데이터를 가져오기 위해 사용했습니다.
    • twilio: WhatsApp 메시지를 발송하기 위해 사용했습니다.
    • datetime: 날짜를 계산하고 API 파라미터로 활용하기 위해 사용했습니다.
  • 외부 APIs:
    • Alpha Vantage: 주식의 시계열 데이터(종가 등)를 받아오기 위해 사용했습니다.
    • News API: 특정 키워드(예: "TESLA")와 관련된 최신 뉴스를 검색하기 위해 사용했습니다.
    • Twilio API for WhatsApp: 처리된 정보를 WhatsApp 메시지로 발송하기 위해 사용했습니다.

 

구현 단계

프로젝트의 전체적인 흐름은 다음과 같습니다: (1) 주가 데이터 수집 → (2) 변동률 계산 → (3) 조건 충족 시 뉴스 수집 → (4) WhatsApp 메시지 발송

1단계: 주가 데이터 수집 및 변동률 계산 (Alpha Vantage)

먼저, 모니터링할 주식의 최근 2거래일 종가 데이터가 필요했습니다. Alpha Vantage의 TIME_SERIES_DAILY 기능을 사용해 일별 주가 데이터를 JSON 형태로 받아왔습니다.

  • API로부터 응답받은 JSON 데이터는 날짜를 key로 갖는 딕셔너리 형태입니다.
  • list(data["Time Series (Daily)"].keys())를 통해 날짜 키(key)들만 추출하여 리스트로 만들었습니다.
  • 이 리스트의 첫 번째 요소([0])가 가장 최근 거래일이며, 두 번째 요소([1])가 그 이전 거래일입니다.
  • 각 날짜의 '4. close' (종가) 값을 가져와 두 거래일 간의 가격 변동률(%)을 계산했습니다.
Python
 
# [중요] API 키 등 민감 정보는 환경 변수 등으로 관리하는 것이 좋습니다.
STOCK_API_KEY = "YOUR_ALPHA_VANTAGE_API_KEY"
STOCK_NAME = "TSLA"

STOCK_PARAMETERS = {
    'function': 'TIME_SERIES_DAILY',
    'symbol': STOCK_NAME,
    'apikey': STOCK_API_KEY
}

response = requests.get("https://www.alphavantage.co/query", params=STOCK_PARAMETERS)
data = response.json()

# 가장 최근 2거래일의 날짜 및 종가 추출
time_series_data = data["Time Series (Daily)"]
all_dates = list(time_series_data.keys())

latest_day = all_dates[0]
latest_day_close = float(time_series_data[latest_day]['4. close'])

previous_day = all_dates[1]
previous_day_close = float(time_series_data[previous_day]['4. close'])

# 변동률 계산
difference = abs(latest_day_close - previous_day_close)
percentage_change = (difference / previous_day_close) * 100

2단계: 조건부 뉴스 기사 수집 (News API)

계산된 변동률이 미리 설정한 임계값(이 프로젝트에서는 3%) 이상일 경우에만 다음 단계를 진행하도록 if 문으로 분기 처리했습니다.

조건이 충족되면 News API를 호출하여 해당 기업(예: "TESLA")과 관련된 최신 뉴스를 검색합니다. 너무 많은 정보를 받는 것을 방지하기 위해, 받아온 전체 기사 중 최근 3개의 기사(all_articles[:3])만 사용했습니다.

Python
 
NEWS_API_KEY = "YOUR_NEWS_API_KEY"
COMPANY_NAME = "Tesla Inc"

# (날짜 계산 로직...)
# today = date.today()
# two_days_ago = today - timedelta(days=2) # 뉴스를 이틀 전부터 검색
# two_days_ago_string = two_days_ago.strftime("%Y-%m-%d")

NEWS_PARAMETERS = {
    'q': COMPANY_NAME, # 또는 "TESLA"
    # 'from': two_days_ago_string, # 검색 시작 날짜
    'apikey': NEWS_API_KEY
}

# 1단계에서 계산한 변동률이 3% 이상일 때
if percentage_change >= 3.0:
    news_response = requests.get("https://newsapi.org/v2/everything", params=NEWS_PARAMETERS)
    news_data = news_response.json()
    
    all_articles = news_data['articles']
    first_three_articles = all_articles[:3] # 상위 3개 기사만 선택

 

3단계: WhatsApp 알림 발송 (Twilio)

마지막으로, 수집한 정보를 바탕으로 WhatsApp 메시지를 발송합니다. Twilio API를 사용했으며, 샌드박스 환경에서 테스트를 진행했습니다.

  • 주가 변동률(🔺 또는 🔻 이모티콘 포함)
  • 기사 제목(Headline), 내용(Description), 원문 URL

위 정보를 포함한 메시지를 기사 3개에 대해 각각 생성하여 발송했습니다.

Python
 
# Twilio 계정 정보 (환경 변수 사용 권장)
TWILIO_ACCOUNT_SID = "YOUR_TWILIO_ACCOUNT_SID"
TWILIO_AUTH_TOKEN = "YOUR_TWILIO_AUTH_TOKEN"
TWILIO_WHATSAPP_NUMBER = "whatsapp:YOUR_TWILIO_SANDBOX_NUMBER" # 예: +14155238886
MY_PHONE_NUMBER = "whatsapp:YOUR_VERIFIED_PHONE_NUMBER" # 예: +821012345678

# ... (기사 수집 로직 이후) ...

    # 메시지 포맷팅
    messages_to_send = [
        f"{STOCK_NAME}: {emoji}{percentage_change:.2f}%\n"
        f"Headline: {article['title']}\n"
        f"Description: {article.get('description', 'No description available.')}\n"
        f"URL: {article['url']}"
        for article in first_three_articles
    ]

    # Twilio 클라이언트 초기화 및 메시지 발송
    client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
    for message_body in messages_to_send:
        message = client.messages.create(
            body=message_body,
            from_=TWILIO_WHATSAPP_NUMBER,
            to=MY_PHONE_NUMBER
        )
        print(f"Message Sent! SID: {message.sid}")

 

겪었던 애로사항 및 고려사항

  1. 날짜 처리의 복잡성 (거래일 기준): 처음에는 datetime 모듈로 '어제'와 '그제' 날짜를 직접 계산하려 했습니다. 하지만 주식 시장은 주말이나 공휴일에 열리지 않습니다. 따라서 오늘이 월요일이라면, '어제(일요일)'와 '그제(토요일)'의 데이터는 존재하지 않습니다. 해결: 날짜를 직접 계산하는 대신, Alpha Vantage API가 반환해주는 Time Series (Daily) 데이터의 key값 순서를 신뢰하기로 했습니다. API 응답의 첫 번째 key(all_dates[0])가 가장 최근 '거래일'이고, 두 번째 key(all_dates[1])가 그 이전 '거래일'임을 활용하여 문제를 해결했습니다.
  2. API 응답 구조(JSON) 파싱: 두 API 모두 중첩된(nested) JSON 구조를 가지고 있습니다. 원하는 데이터(예: 종가, 기사 제목)에 정확히 접근하기 위해 data["Time Series (Daily)"][latest_day]['4. close']처럼 여러 단계의 딕셔너리와 리스트 탐색이 필요했습니다. 이 과정에서 KeyError를 피하기 위해 데이터 구조를 명확히 파악하는 것이 중요했습니다.
  3. Twilio 샌드박스 제약: Twilio를 무료 샌드박스 모드로 사용하면, 메시지를 수신할 번호(제 휴대폰 번호)가 Twilio에 미리 인증되어 있어야 합니다. 또한, 샌드박스 활성화를 위해 특정 키워드(예: join ...)를 샌드박스 번호로 먼저 전송해야 하는 초기 설정 과정이 필요했습니다.
  4. API 무료 등급의 한계: Alpha Vantage와 News API 모두 무료 등급에서는 호출 횟수에 제한이 있습니다. (예: Alpha Vantage는 분당 5회, 일일 25회). 따라서 이 스크립트를 cron이나 스케줄러에 등록하여 너무 자주 실행하면 API가 차단될 수 있습니다. 하루에 한두 번, 장 마감 이후에 실행하는 것이 적절해 보입니다.

 

결론 및 향후 개선점

이 프로젝트를 통해 3개의 각기 다른 API를 연동하여 '데이터 수집 → 가공 → 알림'으로 이어지는 간단한 자동화 파이프라인을 구축해볼 수 있었습니다.

앞으로는 다음과 같은 방향으로 개선할 수 있을 것입니다.

  • 보안 강화: API 키와 같은 민감 정보를 스크립트에 하드코딩하는 대신, os.environ.get()을 사용하여 환경 변수로 관리.
  • 기능 확장: 여러 개의 주식을 동시에 모니터링할 수 있도록 코드 수정.
  • 스케줄링: cron (Linux), taskschd.msc (Windows) 또는 클라우드 서비스(예: AWS Lambda, Google Cloud Functions)를 이용해 매일 특정 시간에 스크립트가 자동으로 실행되도록 설정.
  • 에러 핸들링: API 호출 실패, JSON 파싱 오류 등 예외 상황에 대한 try-except 구문을 추가하여 안정성 향상.
반응형