Today I learned : 선행 연구 조사
선행 연구 조사 및 논거 정리
Sentiment trading with large language models
모델이 어떻게 시장 변화를 예측하고 이를 통한 전략이 높은 성과를 거두는지
-
데이터 수집 및 전처리 : 2010 - 2023까지의 미국 주요 거래소 주식 수익률 데이터 + 글로벌 금융 뉴스 기사(Refinitiv)
수집한 뉴스에서
- 개별 주식과 직접적으로 연관된 뉴스만 선별
- 과거 20일 이내 발행된 다른 기사와 내용이 유사하면(코사인 유사도 0.8 이상) 중복 정보로 간주하여 제외
총 965,375건의 고유한 뉴스 기사 데이터셋
- 사용된 모델 및 파인튜닝
- LLM 파인튜닝 : OPT + BERT 파라미터들을 금융 텍스트 분석에 맞게 미세 조정
-
감성 라벨링
기사 발행 당일과 이후 2일간의 3일 누적 초과 수익률을 기준으로 모델 학습. 주식의 수익률이 시장 수익률보다 양수이면 긍정(1), 아니라면 부정(0)으로 라벨링
실험할 때는 20%, 20% 나누어서 각각 테스트용, 검증용으로 사용
-
주가 예측 모델링
추출된 LLM의 감성 점수가 실제로 다음 날의 주식 수익률을 얼마나 잘 예측하는지 확인하기 위해 선형 회귀 분석을 실시
-
투자 전략 시뮬레이션
롱-숏 정의
롱 : 긍정적인 상위 20% 주식들 매수
숏 : 하위 20% 주식들 공매도
그리고 이 타이밍을 규칙으로 정의
- 미장 열리기 전 : 시가 진입, 종가 청산
- 미장 중 : 당일 종가 진입, 익일 청산
- 미장 닫힌 후 : 다음날 시가에 거래
이것이 어떤 영향을 주는지?
GPT-3 기반 OPT 모델이 다른 모델(BERT, FinBERT)보다 훨씬 뛰어난 성능을 보임, 정확도 74.4%로 주식 시장 수익률 예측
거래 비용의 10bps를 고려한 OPT 기반의 롱-숏(long-short) 전략은 3.05라는 Sharpe ratio를 산출
Leveraging large language model as news sentiment predictor in stock markets: a knowledge-enhanced strategy
https://github.com/XMUT-Service-Computing-Group/GLM-Sentiment
위 CoT를 활용하면 좋을듯. 여기서는 DK-CoT 개념을 제안하였다.
AI에게 뉴스를 던져주고 “긍정이야? 부정이야?”라고 단순히 묻는 대신, 다음 두 가지를 질문(프롬프트)에 포함
- 도메인 지식 (Domain Knowledge, DK): 뉴스를 분석하기 전, 전문가나 데이터베이스를 통해 알아낸 해당 기업의 배경지식(경쟁사 상황, 최근 공시, 재무 상태 등)을 AI에게 먼저 입력
- 사고의 사슬 (Chain-of-Thought, CoT): 정답을 바로 말하지 말고, “이 사건이 기업에 어떤 영향을 미치는지 원인과 결과를 단계별로 추론해 보라”고 지시
SEntFiN 1.0: Entity-aware sentiment analysis for financial news
뉴스 헤드라인에서 감성을 추출하는 방법
feature-based 접근 방식 채택
- 뉴스 헤드라인에는 여러 엔티티가 포함되어 있을 것, 이 뉴스 헤드라인을 여러개의 개별 문장 인스턴스로 재구성
- 각 인스턴스에서 초점이 되는 엔티티를 ‘Target’이라는 단어로 대체
- 이외에 엔티티들은 ‘Other’ 단어로 대체
- 예시
“마힌드라(Mahindra) 주가는 강력한 매출 성장으로 20% 올랐고, 자동차 섹터(auto sector)는 상승세가 예상된다.”
여기서 엔티티는 마힌드라와 자동차 섹터 → 2개의 인스턴스로 재생성
- 첫 번째 문장 (마힌드라가 주인공일 때): “Target 주가는 강력한 매출 성장으로 20% 올랐고, Other는 상승세가 예상된다.”
- 두 번째 문장 (자동차 섹터가 주인공일 때): “Other 주가는 강력한 매출 성장으로 20% 올랐고, Target은 상승세가 예상된다.”
- 그리고 그 Target의 긍정, 부정, 중립을 판별하기 위해 다음 2 step을 진행
-
감성 특징 추출 (정보를 숫자로 바꾸는 원리)
여기서 두 가지 원리를 적용
- Lexicon-based : 금융 도메인에 특화된 5가지 감성 사전을 활용하여 ‘감성 공식’으로 치환
- Pretrained representations : 미리 학습된 AI 모델이 스스로 계산
-
최종 감성들을 판별 (숫자 데이터를 flag로 바꾸는)
분류 알고리즘 사용 : SVM, GBM, MLP, RNN, LSTM과 BiLSTM
-
논문에서 제시한 파라미터 참고한 ipynb
# ========================================== # [셀 1] 패키지 불러오기 및 텍스트 전처리 (Target/Other 치환) # ========================================== import re from sklearn.svm import SVC from xgboost import XGBClassifier from sklearn.neural_network import MLPClassifier from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Embedding, SimpleRNN, LSTM, Bidirectional, Dense, Dropout from tensorflow.keras.optimizers import Adam def preprocess_headline(headline, target_entity, other_entities): """ 논문의 특징 기반(feature-based) 접근 방식을 구현한 간단한 전처리 함수입니다. 관심 있는 엔티티는 'Target'으로, 나머지 엔티티는 'Other'로 치환합니다. """ # 타깃 엔티티 치환 processed_text = headline.replace(target_entity, 'Target') # 나머지 엔티티 치환 for other in other_entities: processed_text = processed_text.replace(other, 'Other') return processed_text # 테스트 예시 sample_headline = "Mahindra & Mahindra's stk up 20% post strong revenue growth ; auto sector likely to see an uptrend" print("인스턴스 1:", preprocess_headline(sample_headline, "Mahindra & Mahindra", ["auto sector"])) print("인스턴스 2:", preprocess_headline(sample_headline, "auto sector", ["Mahindra & Mahindra"])) # ========================================== # [셀 2] 머신러닝 모델 초기화 (Scikit-learn, XGBoost) # ========================================== # 1. SVM: 선형 커널(linear kernel) 및 기본 파라미터 사용 [1, 3] svm_model = SVC(kernel='linear') # 2. GBM (그래디언트 부스팅): 기본 파라미터 사용 [1, 3] gbm_model = XGBClassifier() # 3. MLP (다층 퍼셉트론): 10x10 네트워크 구조, 나머지 기본값 사용 [2, 3] mlp_model = MLPClassifier(hidden_layer_sizes=(10, 10)) print("머신러닝 모델 초기화 완료") # ========================================== # [셀 3] 딥러닝 모델 초기화 (Keras - RNN, LSTM, BiLSTM) # ========================================== # 논문에 명시된 딥러닝 하이퍼파라미터 설정 [3] LEARNING_RATE = 0.01 DROPOUT_RATE = 0.2 NODES = 100 EPOCHS = 10 # 학습 시 활용(model.fit) def build_deep_learning_model(model_type='LSTM', vocab_size=10000, embedding_dim=300, input_length=30): """ model_type: 'RNN', 'LSTM', 'BiLSTM' 중 선택 """ model = Sequential() # 임베딩 레이어 (GloVe 등의 사전 훈련된 가중치를 덧붙일 수 있습니다) model.add(Embedding(input_dim=vocab_size, output_dim=embedding_dim, input_length=input_length)) # 임베딩 레이어 이후 과적합 방지를 위한 Dropout (p=0.2) [3] model.add(Dropout(DROPOUT_RATE)) # 순환 신경망 레이어 구성 (100개의 노드) [3] if model_type == 'RNN': model.add(SimpleRNN(NODES)) elif model_type == 'LSTM': model.add(LSTM(NODES)) elif model_type == 'BiLSTM': model.add(Bidirectional(LSTM(NODES))) # RNN/LSTM 레이어 이후 Dropout (p=0.2) [3] model.add(Dropout(DROPOUT_RATE)) # 출력 레이어: 논문 명시에 따라 sigmoid 활성화 함수 사용 [3] # (긍정, 부정, 중립 3진 분류이므로 노드 수는 3개로 설정) model.add(Dense(3, activation='sigmoid')) # 최적화 알고리즘 ADAM, 학습률 0.01 [3] optimizer = Adam(learning_rate=LEARNING_RATE) model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy']) return model # LSTM 모델 생성 및 요약 출력 lstm_model = build_deep_learning_model(model_type='LSTM') lstm_model.summary()
-
-
흥미롭게도, 딥러닝 없이 ‘어휘 사전 기반 특징(UBT)’을 ‘그래디언트 부스팅(GBM)’ 알고리즘에 넣은 모델 역시 GloVe 등의 임베딩 모델과 맞먹는 매우 뛰어난 성능을 보였습니다. 이는 복잡한 AI 기술 없이도, 금융 도메인 지식(방향성, 조건부 감성 등)을 잘 반영한 규칙과 가벼운 머신러닝 알고리즘만으로도 매우 실용적이고 정확한 감성 판별이 가능함을 시사합니다
이것이 어떤 영향을 주는지?
→ 장기 데이터를 통해 뉴스 감성 지수가 실제 주식 시장의 개장 가격 변동에 유의미한 예측력을 가짐
- 장 마감 후 뉴스의 직접적 영향 : after-market hours 동안 타 시장의 이벤트 등을 통해 축적된 뉴스의 감성 정보는 다음 날 국내 주식 시장의 시가 및 수익률에 유의미한 영향을 미친다.
- 뉴스 기반 감성 지수와 시장 지수(인도 nSE 500)의 30일 이동 평균을 비교한 결과, 두 지표의 장기적인 움직임 사이 상관관계 존재. 감성의 움직임이 주식 시장의 움직임보다 선행하여 나타나는 경향 관찰
https://github.com/pyRis/SEntFiN/tree/main
위 레포에 SEntFin 데이터세트(여러 엔티티가 포함된 금융뉴스 헤드라인과 target-감성 주석 데이터)
금융 엔티티 DB
Sentiment correlation in financial news networks and associated market movements 까지 자세히 정리하지는 못했지만 나는 NER보다는 LLM의 추론을 넣어야 전략에 유의미한 예측이 가능할 거 같음(저 논문에서 NLP의 한계를 언급하며 유의미한 전략은 차세대 모델을 적용해봐야할 거 같다고 함)
그리고 감성 필터가 우선되지 않도록
# 잘못된 방식
if 기술적_조건_충족:
backtest() # 기술적 지표만으로 백테스팅 먼저
if 감성_필터_통과: # 그 후 감성 검사
execute()
# 올바른 방식
if 기술적_조건_충족 AND 감성_필터_통과:
execute() # 두 조건이 백테스트 코드 안에 함께 존재
멘토님 피드백
-
(백테스팅을 제외하고) 비정형 데이터는 검증에 쓰지 않는다.
-
LLM fine-tuning 이라거나 RLHF은 GPU 리소스가 상당히 필요하므로 하지 않음.
-
비정형 데이터는 가공할때 2가지 방법 중 하나를 사용한다. 1) 모델 의존: LLM에게 지정된 형태로 return 하게 하는 가공 2) 레거시 모델 활용: NER 등으로 개체명 인식하고 감성분류모델로 긍/부정을 평가하는 가공
-
비정형 데이터를 수집하는 이유, 활용목적, 기대효과, 수집방법, 출처, 수집 빈도를 정한다.
-
비정형 데이터 가공 결과(만 가지고) -> 매도/매수를 결정하지 않는다.
-
퀀트는 가설수립 - 산술식(로직) 설계 - 근거마련 - 검증 - 폐기 또는 실행 등의 순서를 거치는데 지금의 논의는 조금 막연해보여요. 어느단계에서 어떻게 쓰실것인지, 어떻게 수집할것인지 잘 안보이네요.
-
머릿속에 있는 것으로 논의하기 보다는 논거를 가져와서 동료를 설득하도록 논의하는 방향으로 회의하시고
판관 나으리 이것좀보세요하는 일은 지양한다. -
하락장 예상하고서 선물 거래 하기도하는데 왜 하락장을 예측하면 매도만 하시는것인지(어짜피 가상계좌인데)
-
여러 측면의 데이터를 모으고 분석하는 오케스트레이션은 논리적으로 옳은 방향으로 가는데에 있어서 중요한 과정이고, 각 측면을 어떻게 해석할지는 논거가 정립되어야해요.
-
ML, 강화학습 이쪽에 뜻이 있으신 것이면 이번 프로젝트 환경에서는 그게 좀 어려울것같아요.
논거 정리
[가설]
뉴스 감성이 강하게 부정적인 구간에서 발생한 기술적 매수 신호는 실제 수익으로 이어지지 않을 가능성이 높다. 따라서 감성 필터를 추가하면 false signal을 줄여 Sharpe ratio와 MDD가 개선될 것이다.
[산술식 설계]
진입 조건 = 기술적 조건 충족 AND 감성 점수 >= 임계값
[근거]
근거 1: “부정 감성 구간에서 기술적 신호의 신뢰도가 떨어진다”
Heston & Sinha (2016) — Federal Reserve Board Working Paper 긍정적 뉴스는 주가에 빠르게 반영되지만, 부정적 뉴스는 시장 반응이 장기간 지연되는 비대칭적 패턴이 관찰된다. 즉 부정 감성이 있을 때 주가는 뉴스를 즉각 반영하지 못하고 이후에도 하락 압력이 지속된다. Federal Reserve → 의미: 부정 뉴스가 있는 구간에서 RSI 과매도 신호가 발생해도, 그게 진짜 반등이 아닌 하락 지속 구간일 수 있음. 기술적 신호 단독으로는 이 상황을 구별 못함 Brown (2024) — ScienceDirect 손실 회피 성향을 가진 투자자들은 비관적 뉴스에 과잉반응하는 경향이 있으며, 이로 인해 하락 시장 압력이 강화된다는 것이 실증적으로 확인되었다. ScienceDirect → 의미: 부정 감성이 강할 때 시장은 기술적 분석이 예측하는 것보다 더 하락할 수 있음. 즉 RSI < 30이어도 추가 하락 가능성이 있는 구간 Schmalenbach Journal of Business Research (2024, Springer) 부정 뉴스에 대한 시장 반응이 긍정 뉴스보다 훨씬 강하게 나타나는 비대칭적 패턴이 미국과 유럽 주식시장 모두에서 관찰되었다. 부정 ESG 뉴스는 평균 비정상 수익률 -0.75%를 기록한 반면 긍정 뉴스는 +0.31%에 그쳤다. Springer → 의미: 부정 감성의 시장 충격이 긍정보다 약 2.4배 강함. 기술적 지표가 매수 신호를 내도 부정 감성이 있으면 그 신호를 덮을 가능성이 높음
근거 2: “임계값 설정 근거”
Gómez-Martínez et al. (2025, SAGE Open, SSCI) 기술적 지표(RSI, MACD, 볼린저밴드)로만 구성된 전략에 감성 지표를 필터로 추가했을 때, 순이익은 감소했지만 Sharpe ratio와 최대 낙폭 등 리스크 관리 지표가 일관되게 개선되었다. 이는 감성 필터가 수익 극대화보다 false signal을 줄이는 리스크 필터로 기능함을 시사한다. Sage Journals → 의미: 임계값의 목적은 수익 극대화가 아니라 손실 방어. 임계값은 백테스팅으로 최적화하되, 목표 지표를 MDD 개선으로 설정하는 것이 논리적
- LLM을 활용할 때 GLM에서 만든 CoT를 레퍼런스 삼아 사용하는 게 어떤지
- 데이터 수집, 전처리에 관해서는 Sentiment trading with large language models 이 방법을 따라가는 게 좋아보임. 다만 우리는 국내 솔루션이니까 로컬라이징이 필요하고, 우리의 프로젝트에 녹이려면 아래와 같은 고민 필요 a. 우리는 롱-숏 전략만 채택하지 않는데 여러 전략에 대해 어떻게 이것을 사용할 것인지 b. 해당 논문은 fine-tuning을 사용하였는데 우리의 프로젝트에서는 멘토링대로 활용이 조금 어렵고 LLM의 추론에 의지해야되는 부분이 있음. 이는 어떻게? c. 비정형 데이터 가공 결과(만 가지고) -> 매도/매수를 결정하지 않는다. 고 멘토링 받았는데 기존 기술 지표들과 어떻게 하이브리드로 사용할 것인지
- 위 의견에서 말하는 임계값은 어떻게 설정?
a. 우리는 롱-숏 전략만 채택하지 않는데 여러 전략에 대해 어떻게 이것을 사용할 것인지
Rule-Based RSI + Sentiment (MDPI Electronics, 2025) RSI가 과매도 신호를 보내더라도 뉴스 감성이 강하게 긍정적이면 매수 신호를 강화하고, RSI가 과매수 신호를 보내더라도 감성이 강하게 부정적이면 하락 압력을 반영해 매도 신호를 보강하는 규칙 기반 하이브리드 구조를 설계했다. MDPI → 차용할 아이디어: 전략 유형에 상관없이 “기술적 지표 조건 충족 + 감성 필터 통과” 이중 조건 구조로 설계 가능. 모멘텀 전략이든 평균회귀 전략이든 동일하게 적용됨
[입력] 티커 심볼 (예: AAPL)
↓
[데이터 수집]
- 주가 데이터: 최근 30거래일 OHLCV (Polygon.io)
- 뉴스 데이터: 최근 7일 뉴스 기사 최대 100개 (NewsAPI)
↓
[병렬 전처리]
좌측: RSI 계산 우측: 감성 점수 계산
14일 RSI TextBlob으로 각 기사 극성(-1~+1) 추출
7일 RSI 이동평균 평균 극성 계산
1~100으로 스케일링
(평균극성 + 1) × 50
↓
[의사결정 — 이중 조건 AND 구조]
여기서 TextBlob 감성 점수는 레거시 NLP 방식 차용
b. 해당 논문은 fine-tuning을 사용하였는데 우리의 프로젝트에서는 멘토링대로 활용이 조금 어렵고 LLM의 추론에 의지해야되는 부분이 있음. 이는 어떻게?
MarketSenseAI (Fatouros et al., 2024) GPT-4를 파인튜닝 없이 Chain-of-Thought 프롬프트와 in-context learning만으로 투자 시그널을 생성하고, 이를 종목 선정에 활용하여 해석 가능하고 수익성 있는 투자 신호를 만들어냈다.
[News Agent] → 뉴스 기사 수집·요약
[Fundamentals Agent]→ 재무제표 + SEC 공시 + 어닝콜 분석
[Dynamics Agent] → 주가 흐름 + 리스크 지표(Sharpe, MDD)
[Macro Agent] → 중앙은행 리포트, 투자은행 분석 등 거시경제
↓ (4개 에이전트 출력을 통합)
[Signal Agent] → CoT 프롬프트로 Buy/Hold/Sell 결정 + 근거 설명
c. 비정형 데이터 가공 결과(만 가지고) -> 매도/매수를 결정하지 않는다. 고 멘토링 받았는데 기존 기술 지표들과 어떻게 하이브리드로 사용할 것인지
핵심 레퍼런스: Gómez-Martínez et al. (SAGE Open, SSCI, 2025) 기술적 지표(이동평균, RSI, MACD, 볼린저밴드) 기반 전략에 감성 지표를 필터로 추가했을 때, 순수 AI 전략(ML로 방향 예측)보다 순이익은 낮았지만 Sharpe ratio, 변동성, 최대 낙폭 등 리스크 관리 지표에서 일관되게 우월한 결과를 보였다. Sage Journals → 차용할 아이디어: 감성은 수익 극대화보다 리스크 필터 역할에 강점이 있음
3. 위 의견에서 말하는 임계값은 어떻게 설정?
import numpy as np
# 감성 임계값 후보군
thresholds = np.arange(-1.0, 1.0, 0.1) # -1.0, -0.9, ..., 0.9
best_theta = None
best_mdd = float('inf')
for theta in thresholds:
# 해당 theta로 백테스팅 실행
result = run_backtest(
strategy="RSI",
sentiment_threshold=theta,
data=historical_data
)
mdd = calculate_mdd(result['returns'])
if mdd < best_mdd:
best_mdd = mdd
best_theta = theta
print(f"최적 theta: {best_theta}, MDD: {best_mdd}")
이거를 구간 분할해서 기간마다의 theta 최적화하고 다음 구간에서 성과 측정하며 최적화
scipy 같은 거 사용하는 방법도 있긴 함