2. quant 프로젝트 회고
이번 글은 프로젝트를 만들면서 어떤 프레임워크와 라이브러리를 고를지, 그리고 외부 API를 어디까지 믿고 어디서 방어할지를 고민했던 과정을 정리한 회고이다. 개발을 시작할 때는 "좋아 보이는 기술 스택"보다 "이 문제를 누가 가장 잘 해결할 수 있는가"를 먼저 생각하려고 했다. 퀀트 프로젝트는 특히 이 판단이 중요했다.
1. 주제 소개
[ 핵심 개념 ]
이 프로젝트는 크게 세 가지 성격이 섞여 있다.
- 화면이 많은 제품형 웹 애플리케이션
- 백엔드 도메인 로직과 데이터 저장이 중요한 서비스
- 수치 계산과 데이터 가공이 많은 분석 엔진
하나의 언어와 프레임워크로 모두 밀어붙일 수도 있었지만, 실제로는 각 영역의 강점이 꽤 다르다고 느꼈다. 즉, 어떤 기술을 고를지 고민하는 과정은 취향의 문제가 아니라 책임 분리의 문제였다.
[ 왜 필요한가? ]
예를 들어 화면을 빠르게 만들고 싶다면 Next.js가 강점이 있고, 트랜잭션과 도메인 모델을 안정적으로 관리하려면 Spring Boot가 익숙하고 강하다. 반대로 백테스트나 팩터 계산처럼 수치 연산과 데이터 분석이 많은 부분은 Python 생태계가 훨씬 풍부하다.
문제는 각각의 장점이 분명한 만큼, 잘못 섞으면 복잡성만 늘어난다는 점이다. 그래서 기술 선택 기준을 아래처럼 잡았다.
- UI 생산성과 상태 관리가 좋은가
- API와 DB 중심 비즈니스 로직을 안정적으로 다룰 수 있는가
- 데이터 분석 라이브러리를 자연스럽게 활용할 수 있는가
- 외부 데이터 소스를 붙일 때 구현 난도가 과도하게 올라가지 않는가
- 나중에 장시간 작업과 운영 모니터링까지 확장 가능한가
2. 프레임워크를 고를 때 했던 고민
[ Next.js를 선택한 이유 ]
화면 쪽은 Next.js로 정리했다. 이유는 단순했다. 이 프로젝트는 대시보드 하나만 있는 앱이 아니라, 전략 만들기, 백테스트, 포트폴리오, 데이터 센터, 뉴스 분석처럼 페이지와 상태 전환이 많다. 이런 구조에서는 라우팅, 서버 컴포넌트, 로딩 상태 분리가 자연스러운 프레임워크가 필요했다.
특히 UI에서 중요했던 점은 아래와 같다.
- 페이지 단위 로딩 경험을 세밀하게 설계할 수 있는가
- 서버 데이터와 클라이언트 상호작용을 적절히 섞을 수 있는가
- 모듈이 많아져도 폴더 구조가 감당 가능한가
Next.js는 화면 단위 구성이 비교적 명확해서, 15개 모듈을 나누는 데 부담이 적었다.
[ Spring Boot를 가운데 둔 이유 ]
처음에는 Python만으로도 API 서버를 구성할 수 있지 않을까 생각했다. 실제로 계산 엔진은 Python이 더 자연스럽기 때문이다. 그런데 프로젝트를 넓게 보니 계산만 있는 것이 아니었다.
- 전략 저장
- 포트폴리오 관리
- 주문과 실행 상태 관리
- 작업 이력 조회
- 사용자 흐름에 맞춘 API 응답 조립
이런 영역은 계산 정확성보다 도메인 모델과 트랜잭션 안정성이 더 중요했다. 그래서 Spring Boot를 중앙 허브로 두고, Python은 계산 엔진으로 분리하는 편이 훨씬 낫다고 판단했다.
다시 말해 Spring Boot는 "계산을 직접 다 하는 서버"가 아니라, 화면과 계산 엔진과 DB를 연결하는 플랫폼 레이어 역할을 맡도록 설계했다.
[ Python은 계산 엔진에 집중시키는 쪽이 맞았다 ]
Python 쪽은 FastAPI 기반으로 두되, 역할을 명확히 제한했다.
- 시장 데이터 가공
- 종목 후보 점수 계산
- 백테스트
- 최적화
- 리스크 계산
- 뉴스와 이벤트 기반 보조 분석
이렇게 분리하니 장점이 있었다. 계산 코드가 Kotlin 서비스 계층 안으로 흩어지지 않고, pandas나 numpy, vectorbt 같은 분석 생태계를 그대로 활용할 수 있었다.
3. 라이브러리 선택에서 고민했던 지점
[ 라이브러리는 기능이 아니라 비용도 함께 본다 ]
처음에는 필요한 기능만 되면 된다고 생각했다. 그런데 퀀트 프로젝트에서는 라이브러리 하나를 들여오는 순간 그 라이브러리의 데이터 형식, 에러 방식, 성능 특성, 운영 리스크까지 함께 받아오게 된다.
예를 들어 Python 쪽에서는 이런 성격이 섞여 있었다.
pandas,numpy,scipy,statsmodels- 시계열과 수치 계산의 기본 도구
vectorbt- 백테스트 계산을 빠르게 조합하는 데 유리
requests- 외부 데이터 수집용 HTTP 클라이언트
하지만 중요한 것은 "쓸 수 있는가"보다 "이 프로젝트 흐름에 맞는가"였다. 예를 들어 데이터 프레임 중심 라이브러리는 계산에는 강하지만, 서비스 관점에서 입력 검증과 예외 메시지를 따로 챙겨야 했다. 그래서 FastAPI와 Pydantic으로 API 계약을 분리하고, 계산은 내부 서비스에서 처리하는 식으로 계층을 나누었다.
[ 외부 API는 편리함보다 일관성이 중요했다 ]
외부 API 선택은 더 보수적으로 봤다. 현재 프로젝트에서 직접 쓰는 데이터 소스는 크게 아래 축으로 정리되었다.
- Yahoo Finance 계열 데이터
- NewsAPI
- SEC EDGAR / SEC Data
- Nasdaq Trader Symbol Directory
- KRX KIND
문제는 이들이 서로 다른 성격을 가진다는 점이다.
- 어떤 소스는 가격 이력에는 강하지만 종목 메타데이터가 약하다
- 어떤 소스는 미국 종목 공시 데이터는 좋지만 한국 종목에는 쓸 수 없다
- 어떤 소스는 검색과 편의성은 좋지만 운영 안정성을 따로 봐야 한다
그래서 한 공급자에 모든 것을 기대하기보다, 역할을 나눠서 쓰는 방향이 더 현실적이었다.
4. 외부 API를 붙일 때 실제로 고민했던 것
[ Yahoo Finance를 쓸 때의 고민 ]
Yahoo Finance 계열 데이터는 빠르게 시작하기 좋다. 시세, 심볼 검색, 일부 프로필, 이벤트성 데이터까지 접근 폭이 넓다. 하지만 여기서 바로 운영 시스템처럼 믿고 가는 것은 조심해야 했다.
내가 고민했던 포인트는 아래와 같았다.
- 시세는 편리하지만 데이터 정합성을 어디까지 보장할 것인가
- 검색 결과가 항상 원하는 거래소 분류를 정확히 주는가
- 미국과 한국 심볼 체계를 같은 규칙으로 다뤄도 되는가
- rate limit이나 응답 변형에 어떻게 대응할 것인가
그래서 프로젝트에서는 Yahoo Finance를 핵심 진입점으로 쓰되, 펀더멘털은 SEC 데이터를 보강하고, 종목 유니버스는 Nasdaq Trader와 KRX KIND를 따로 붙여서 신뢰도를 나눠 가져가도록 설계했다.
[ NewsAPI를 붙일 때의 고민 ]
뉴스 기능은 생각보다 단순하지 않았다. 뉴스 원문 자체보다도, 어떤 종목과 연결할지, 감성 점수를 어떻게 붙일지, 번역은 어디서 처리할지까지 이어졌다. NewsAPI는 이 중 "뉴스 수집"을 빠르게 해결해 주지만, 기사 품질이나 종목 연결까지 해결해 주는 것은 아니다.
즉, 뉴스 API는 시작점일 뿐이었다. 실제 기능은 그 뒤에 붙는 엔티티 추출, 감성 분석, 영향도 계산, 캐시 전략까지 함께 설계해야 했다.
[ SEC를 붙인 이유 ]
미국 종목 펀더멘털은 결국 공시 기반 데이터가 필요했다. 시가총액이나 단순 프로필은 다른 소스에서도 얻을 수 있지만, 매출, 순이익, EPS, 자본총계 같은 항목은 SEC 기반으로 가져와야 계산 근거가 더 명확해진다.
여기서 중요한 점은 SEC를 단순 조회 API처럼 쓰는 것이 아니라, 캐시와 가공 파이프라인까지 포함한 데이터 소스로 다뤄야 한다는 점이었다. 즉, "가져오기"보다 "다운로드 후 어떻게 적재하고 합칠 것인가"가 더 큰 문제였다.
5. 예시로 이해하기
예를 들어 미국 종목 하나를 등록한다고 해보자. 필요한 데이터는 한 곳에서 끝나지 않는다.
- 종목 검색과 기본 시세: Yahoo Finance 계열
- 상장 종목인지 확인: Nasdaq Trader
- 회사 프로필과 공시 기반 재무 데이터: SEC
- 뉴스 분석: NewsAPI
이 흐름을 처음부터 한 공급자에 다 맡기려 했다면 기능은 빨리 시작할 수 있어도 금방 막혔을 가능성이 크다. 반대로 공급자를 분리하니 구현은 조금 더 복잡해졌지만, 각 데이터의 역할이 명확해졌다.
6. 장점 / 한계 / 주의사항
[ 선택이 잘 맞았던 부분 ]
- 화면, 도메인, 계산이 서로 다른 속도로 발전할 수 있었다
- Python 생태계의 계산 강점을 그대로 활용할 수 있었다
- Spring Boot가 중간에서 계약과 저장 구조를 안정적으로 잡아줬다
- 외부 API를 역할별로 분리해 데이터 해석이 쉬워졌다
[ 아쉬웠던 부분 ]
반대로 스택이 분리될수록 공통 타입과 에러 메시지 관리가 귀찮아진다. 프론트, Kotlin, Python이 같은 의미를 다르게 표현하면 디버깅 비용이 바로 커진다. 예를 들어 상태값, 날짜 형식, 진행률 메타데이터, 필드명 표기 방식은 작은 차이로도 운영 피로도가 올라간다.
[ 주의할 점 ]
프레임워크를 고를 때 "가장 인기 있는 것"보다 "이 프로젝트의 책임 분리와 잘 맞는가"를 먼저 봐야 한다. 외부 API도 마찬가지다. 데이터가 많이 나온다는 이유만으로 고르면, 나중에는 정합성 문제와 예외 처리 비용을 더 크게 치르게 된다.
7. 정리
정리하면, 이 프로젝트의 기술 선택은 유행보다 역할 분리에 더 가깝다. Next.js는 화면 경험과 모듈 구성을 담당하고, Spring Boot는 플랫폼 중심 로직과 저장 구조를 맡고, Python은 퀀트 계산 엔진에 집중하도록 두었다. 외부 API도 한 곳에 몰아넣기보다, 시세, 종목 마스터, 공시, 뉴스처럼 역할별로 분리해 쓰는 편이 더 현실적이었다.
결국 중요한 것은 기술을 많이 쓰는 것이 아니라, 각 기술이 어떤 문제를 해결하는지 분명히 아는 것이다. 따라서 프레임워크와 외부 API를 고를 때는 편의성뿐 아니라 운영 비용과 데이터 신뢰도까지 함께 보는 시각이 꼭 필요하다고 느꼈다.