
1. 📌 개요
BackEnd 지식을 쌓고 API 제작 구현을 익숙해지기 위해 사이드 프로젝트를 시작하였다.
해당 글에서는 FastAPI를 활용하여 주식 분석 API를 개발에 대해 기술하고,
API 요청 처리 방식과 주요 기능 구현 과정을 기록한다.
Git repo는 다음 링크과 같다.
https://github.com/WellshCorgi/dev-infinity-api
GitHub - WellshCorgi/dev-infinity-api: A project focused on continuously developing various features, designing efficient APIs,
A project focused on continuously developing various features, designing efficient APIs, and documenting the process along the way. - WellshCorgi/dev-infinity-api
github.com
2. 📌 프로젝트 구조
<bash />. ├── API_Readme │ └── Stock_README.md ├── app │ ├── core │ │ ├── config.py │ │ └── stock_analysis.py │ └── routers │ └── stock.py ├── main.py └── tests └── test_stock.py
디렉토리는 FastAPI 공식문서를 참조했다.
search keyword : fastapi structure official document
https://fastapi.tiangolo.com/tutorial/bigger-applications/#import-apirouter
3. 📌 FastAPI 요청 처리 방식
1. FastAPI의 라우터 분리
FastAPI에서는 APIRouter를 활용하여 각 기능별로 엔드포인트를 분리할 수 있다.
이로써 API 추가 개발 시 , app.include_router(bigbang.router) 를 넣을 수 있다.
<bash />
from fastapi import FastAPI
from app.routers import stock
def create_app():
"""FastAPI 애플리케이션 생성 함수"""
#라우터 등록
app = FastAPI(title="dev-infinity API by WellshCorgi", version="1.0")
app.include_router(stock.router)
return app
이렇게 하면 각 API를 독립적으로 관리할 수 있어서 코드 유지보수와 확장성이 좋아진다.
2. 요청 처리 흐름
🔹 (1) 클라이언트 요청 → FastAPI 라우터에서 처리
- /stock/AAPL → 특정 주식(AAPL)의 데이터를 가져와 분석
🔹 (2) 요청을 받은 후, 비즈니스 로직 실행
- core/stock_analysis.py → yfinance를 활용해 주식 데이터를 조회하고 이동평균선 분석
🔹 (3) JSON 응답 반환
FastAPI에서는 dict를 리턴하면 자동으로 JSON 형식으로 변환해준다.
<python />
{
"symbol": "AAPL",
"current_price": 175.23,
"50_day_MA": 170.45,
"200_day_MA": 160.78,
"RSI": 52.3,
"MACD": 1.23,
"MACD_signal": 1.10,
"signals": ["Buy (Golden Cross)"]
}
4. 📌 API 구현 코드
1. 구현 동기
최근 주식 투자자들은 기술적 지표를 활용한 분석을 통해 거래를 진행한다. 이에 따라 yfinance 라이브러리를 사용하여 주식 데이터를 기반으로 RSI, MACD, 이동 평균선 등의 지표를 계산하고 매매 신호를 제공하는 API를 개발하게 되었다.
개발하며 라이브러리를 활용할 때, 기본적으로 어떻게 처리(반환)하는지 어떠한 기능이 있는지 공식문서나 github을 확인하는것이 중요하다.
https://ranaroussi.github.io/yfinance/index.html
yfinance documentation — yfinance
IMPORTANT LEGAL DISCLAIMER Yahoo!, Y!Finance, and Yahoo! finance are registered trademarks of Yahoo, Inc. yfinance is not affiliated, endorsed, or vetted by Yahoo, Inc. It’s an open-source tool that uses Yahoo’s publicly available APIs, and is intended
ranaroussi.github.io
https://pypi.org/project/yfinance/
Client Challenge
JavaScript is disabled in your browser. Please enable JavaScript to proceed. A required part of this site couldn’t load. This may be due to a browser extension, network issues, or browser settings. Please check your connection, disable any ad blockers, o
pypi.org
2. 주요 기능
- 주식 데이터 조회:
- yfinance를 이용해 특정 종목의 1년간 주가 데이터를 받는다.
- 종목 코드(ticker)를 입력하면 해당 데이터가 반환된다.
- 기술적 지표 계산:
- RSI(Relative Strength Index): 과매수(>70) 또는 과매도(<30) 여부 확인
- MACD(Moving Average Convergence Divergence): 매수·매도 신호 판단
- 이동 평균선(50일, 200일): 골든크로스/데드크로스 감지
- 볼린저 밴드: 주가가 밴드 상·하단에 위치하는지 확인
- 매매 신호 제공:
- 기술적 지표를 종합적으로 분석하여 Buy(매수), Sell(매도), Neutral(중립) 신호를 반환
경제 지표에 대해서는 뚜렷한 지식이 없기에 구글링을 통해 대략적으로 지식을 습득하여 구현하였다.
(미국장 투자하는데 자세히 모르고 투자하는 1인)
3. 요청 및 응답 구조
GET /stock/{symbol}
- 종목(symbol) 입력 시 최근 6개월 데이터를 기반으로 매수 여부 판단
- 현재 가격과 50일 이동평균선을 비교하여 분석
app/core/stock_analysis.py
<python />
def get_stock_data(ticker: str):
"""주어진 종목(ticker)의 주가 데이터 조회"""
try:
stock = yf.Ticker(ticker)
df = stock.history(period="1y") # 1년치 데이터 가져오기
if df.empty:
raise ValueError(f"Unable to fetch data: {ticker}")
return df
except Exception as e:
raise HTTPException(status_code=404, detail=f"Invalid ticker or no data available: {str(e)}")
period="1y"를 활용하여 1년데이터를 가져올수 있었다.
<python />
def analyze_stock(ticker: str):
"""매수/매도 판단"""
df = get_stock_data(ticker)
# 이동 평균, RSI, MACD 계산
df["50_MA"] = df["Close"].rolling(window=50).mean()
df["200_MA"] = df["Close"].rolling(window=200).mean()
df["RSI"] = calculate_rsi(df)
df["MACD"], df["MACD_signal"] = calculate_macd(df)
current_price = df["Close"].iloc[-1]
ma50 = df["50_MA"].iloc[-1]
ma200 = df["200_MA"].iloc[-1]
rsi = df["RSI"].iloc[-1]
macd = df["MACD"].iloc[-1]
macd_signal = df["MACD_signal"].iloc[-1]
# 거래량 (Volume) 추가 - 거래량이 증가하는 조건 추가
volume_avg = df["Volume"].rolling(window=30).mean().iloc[-1]
current_volume = df["Volume"].iloc[-1]
# 신호 목록을 구조화된 데이터로 저장
signals = []
# 골든 크로스 / 데드 크로스
if df["50_MA"].iloc[-2] < df["200_MA"].iloc[-2] and ma50 > ma200:
signals.append({"type": "Buy", "reason": "Golden Cross (50-day MA > 200-day MA)"})
if df["50_MA"].iloc[-2] > df["200_MA"].iloc[-2] and ma50 < ma200:
signals.append({"type": "Sell", "reason": "Dead Cross (50-day MA < 200-day MA)"})
# RSI 기반 과매수 / 과매도 판단
if rsi < 30:
signals.append({"type": "Buy", "reason": "RSI Oversold (<30)"})
elif rsi > 70:
signals.append({"type": "Sell", "reason": "RSI Overbought (>70)"})
# 볼린저 밴드 활용
bb_upper = df['Close'].rolling(window=20).mean() + (df['Close'].rolling(window=20).std() * 2)
bb_lower = df['Close'].rolling(window=20).mean() - (df['Close'].rolling(window=20).std() * 2)
if current_price < bb_lower.iloc[-1]:
signals.append({"type": "Buy", "reason": "Price near lower Bollinger Band"})
elif current_price > bb_upper.iloc[-1]:
signals.append({"type": "Sell", "reason": "Price near upper Bollinger Band"})
# MACD 상향 돌파 / 하향 돌파
if df["MACD"].iloc[-2] < df["MACD_signal"].iloc[-2] and macd > macd_signal:
signals.append({"type": "Buy", "reason": "MACD bullish crossover"})
elif df["MACD"].iloc[-2] > df["MACD_signal"].iloc[-2] and macd < macd_signal:
signals.append({"type": "Sell", "reason": "MACD bearish crossover"})
# 추가적인 매매 신호 조건
if current_price > ma50 and rsi < 40 and macd > macd_signal and current_volume > volume_avg:
signals.append({"type": "Buy", "reason": "Multiple buy signals (MA, RSI, MACD, Volume)"})
if current_price < ma50 and rsi > 60 and macd < macd_signal and current_volume > volume_avg:
signals.append({"type": "Sell", "reason": "Multiple sell signals (MA, RSI, MACD, Volume)"})
return {
"symbol": ticker,
"current_price": round(current_price, 2),
"50_day_MA": round(ma50, 2),
"200_day_MA": round(ma200, 2),
"RSI": round(rsi, 2),
"MACD": round(macd, 2),
"MACD_signal": round(macd_signal, 2),
"signals": signals if signals else [{"type": "Neutral", "reason": "No clear trading signal"}]
}
signal = [] 리스트를 활용하여 각종 지표에 대한 임계값이 넘으면 반환하기 위해 신호목록을 append하는 방식으로 구현하였다.
5. 📌 결론
이 API를 활용하면 주식 데이터를 자동으로 분석하여 기술적 매매 신호를 제공한다.
AI 모델을 활용한것이 아니라 기본 지표에 대한 판별이니 참고용으로 활용하자.
'Develop & Project Review' 카테고리의 다른 글
[API] 로또 당첨 번호 조회 및 추천 번호 생성 (Check the lottery winning number and generate the number) (1) | 2025.02.17 |
---|---|
[Project] K3s 기반 라즈베리 클러스터 구축 및 엣지 디바이스 모니터링 구현 (3) | 2024.07.09 |
2024 Winter - Spurt Project - 2 (프리즈마 작성 및 MVC 리팩토링) (1) | 2024.01.23 |
2024 Winter - Spurt Project - 1 [스터디 개인 프로젝트] (0) | 2024.01.16 |
[React] FireBase를 활용한 Login 기능 구현 (2) | 2023.11.15 |