
🧠📉 AI + 주식 자동매매 프로젝트 공유
2편. 감성 분석 기반 시그널 실험 — 뉴스·트위터·리포트로 투자심리 점수 만들기
감성 분석은 “시장 분위기(센티먼트)”를 수치화해서 시그널로 활용하는 핵심 기술입니다.
특히 미국 시장은 뉴스 한 줄 또는 트위터 한 문장으로 주가가 크게 움직이기 때문에,
감성 분석 기반 점수는 백테스트/실전 매매에서 꽤 유의미한 신호가 됩니다.
이번 글에서는 제가 실제로 구축했던
(1) 데이터 수집 → (2) 감성 라벨링 → (3) LLM 기반 투자심리 점수화 → (4) 시그널 실험
전체 과정을 실무 중심으로 정리합니다.
1. 감성 데이터 수집 구조
[데이터 소스]
├─ News API (Google News, Benzinga, SeekingAlpha)
├─ Twitter/X 크롤링 (snscrape 기반)
├─ 증권사 리포트(요약본)
[처리 레이어]
├─ 텍스트 정제(HTML 제거, 중복 제거)
├─ 영향도 기반 가중치 계산 (조회수 / 리트윗 수 / 언급량)
[저장]
├─ Raw JSON
├─ Clean Text
└─ Sentiment Scores
감성 분석은 “데이터 품질”이 승부를 가릅니다.
특히 중복 기사, 봇 트윗, 단순 광고 기사는 제거해야 왜곡을 막을 수 있습니다.
2. 뉴스 크롤링 예시 (Benzinga + Google News)
from GoogleNews import GoogleNews
import pandas as pd
def fetch_news(keyword, days=3):
googlenews = GoogleNews(lang='en', period=f"{days}d")
googlenews.search(keyword)
result = googlenews.results()
df = pd.DataFrame(result)
df["keyword"] = keyword
return df[["title", "desc", "date", "media", "link", "keyword"]]
실전에서 겪은 문제
- GoogleNews 패키지는 종종 실패 → 에러 시 재시도 + User-Agent 랜덤 적용
- 제목(title)만 보면 감정 예측이 잘 안됨 → 본문 크롤링 병행 필요
3. 트위터(X) 감성 데이터 수집 (snscrape 기반)
import snscrape.modules.twitter as sntwitter
import pandas as pd
def fetch_tweets(keyword, limit=200):
tweets = []
for i, tweet in enumerate(sntwitter.TwitterSearchScraper(keyword).get_items()):
if i > limit:
break
tweets.append([tweet.date, tweet.user.username, tweet.content])
return pd.DataFrame(tweets, columns=["date", "user", "text"])
실무 경험
- X API 유료화 이후 대부분 snscrape 사용
- 광고·스팸 계정이 매우 많음 → 정규식/키워드 기반 필터링 필수
4. 감성 분석 모델 구성 (ML + LLM 하이브리드)
실전에서는 딥러닝 하나만 쓰지 않습니다.
ML + LLM 조합이 가장 안정적이고 잡음이 적었습니다.
아키텍처
[1차 분류] → ML 기반 감성 모델 (영문 금융 특화)
├─ FinBERT (긍·부정·중립 분류)
[2차 보정] → LLM 기반 의미 분석
├─ GPT-4o / Llama-3 (문맥 기반 보정)
├─ 투자 영향도 산출 (Impact Score)
[최종] → Sentiment Score 종합
score = f(FinBERT, LLM, 트윗 영향도, 뉴스 출처 신뢰도)
FinBERT 예시 코드
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
tokenizer = AutoTokenizer.from_pretrained('ProsusAI/finbert')
model = AutoModelForSequenceClassification.from_pretrained('ProsusAI/finbert')
def finbert_sentiment(text):
inputs = tokenizer(text, return_tensors='pt', truncation=True)
outputs = model(**inputs)
probs = torch.nn.functional.softmax(outputs.logits, dim=1)
return probs.detach().numpy()[0]
5. LLM 기반 투자심리 점수 보정
LLM을 쓰는 이유는 간단합니다.
“긍정인데 실제 시장 반응은 악재” 같은 케이스를 잡기 위해서입니다.
프롬프트 예시
다음 뉴스가 특정 종목 주가에 미치는 영향을 다음 기준으로 평가해라.
- 범위: -1.0(강한 악재) ~ +1.0(강한 호재)
- 고려 요소: 공급망/실적/규제/메가트렌드/리스크
- 시장에 바로 반응할 만한 구문을 특히 가중치 높게
뉴스 본문:
{news_text}
LLM의 점수와 FinBERT 점수를 평균내지 않고,
가중치(출처 신뢰도/기사 길이/키워드 위험도)를 반영하여 계산합니다.
6. 감성 기반 시그널 생성
예시: S&P500 종목에 적용한 시그널 로직
① 최근 24시간 뉴스 감성 평균값 = S_news
② 최근 24시간 트윗 감성 평균값 = S_tweet
③ 키워드 위험도(리스크 워딩) = S_risk
최종 점수 = 0.5*S_news + 0.3*S_tweet + (-0.2)*S_risk
매매 규칙 예시
최종 점수 시그널 행동
| ≥ +0.3 | 매수 | 1단계 비중 진입 |
| ≥ +0.6 | 강한 매수 | 2단계 비중 확대 |
| ≤ -0.3 | 매도 | 전량 청산 또는 헷지 |
| 중립 | 홀딩 | 변동 없음 |
7. 백테스트 결과(실제 경험)
- 기술적 지표만 썼을 때보다 MDD(최대 낙폭) 12~18% 감소
- 급락장(뉴스 충격)에서 손실 회피가 확실히 잘됨
- 상승장에서는 +α 수익은 크지 않지만 리스크 관리 성능이 뛰어남
특히 연준·금리·승인/거부 뉴스에 빠르게 반응하는 종목에서 효과가 컸습니다.
8. 실전 팁 3가지
✔ TIP 1. 기사 100개보다 “중요 기사 10개”가 더 정확함
조회수/공유량/출처 신뢰도 기준으로 가중치 필터링을 넣으면 점수 품질이 2배 좋아집니다.
✔ TIP 2. 감성 점수는 절대 “평균값”으로만 쓰지 말 것
뉴스가 90% 긍정인데, 단 한 개의 강력한 악재 기사가 터지면
실제 시장은 악재로 반응합니다.
→ Worst Score / Shock Score를 함께 넣는 게 핵심.
✔ TIP 3. LLM은 메인 모델이 아니라 “보정 모델”로
빠르고 안정적인 FinBERT로 1차 분류 →
LLM은 “보정 + 해석 + 충격도 판단”에만 사용하면
속도·비용·정확도 모두 균형 잡힙니다.
다음 편 예고
3편. 백테스트 시스템 만들기 — 실전급 백테스트 엔진 설계와 구현
- 백테스트 엔진 아키텍처
- 슬리피지/수수료/체결 지연 처리
- 멀티 종목 포트폴리오 백테스트
- UI 없이 데이터 기준으로 빠르게 검증하는 방법
📌 추천 태그
#자동매매 #AI투자 #감성분석 #LLM투자 #FinBERT
#투자심리 #데이터엔지니어링 #퀀트 #뉴스데이터 #백테스트
'AI 기반 자동매매 & 금융데이터 분석' 카테고리의 다른 글
| 5편. 실시간 자동매매 시스템 구축 — FastAPI · vLLM · 전략 Executor 설계 (0) | 2025.12.05 |
|---|---|
| 4편. ML + LLM 기반 시그널 생성 실험기 — 모델 학습·검증·운영 파이프라인 (0) | 2025.12.05 |
| 3편. 백테스트 시스템 만들기 — 실전급 백테스트 엔진 설계와 구현 (0) | 2025.12.05 |
| 1편. 국내/미국 주식 데이터 수집 자동화 실전 가이드 (0) | 2025.12.05 |
| TimeParents v1.2.0 — Windows Game Time Management Tool for Kids (0) | 2025.11.30 |