AppOrbit
Back to DevLog

Next.js 16으로 나만의 주식 투자 비서 만들기 (터틀 트레이딩 알고리즘 구현기)

Next.jsTypeScriptSide ProjectAlgorithmFinance

1. 들어가며: 왜 이 서비스를 만들었나?

"차트를 하루 종일 보고 있자니 눈이 너무 아프다."

주식 투자를 공부하면서 전설적인 '터틀 트레이딩(Turtle Trading)' 기법을 접했습니다. 원칙 자체는 명확했습니다. "20일 신고가를 갱신하면 사고, 10일 신저가를 찍으면 팔아라." 하지만 직장인이 매일 500개가 넘는 S&P 500 종목의 차트를 돌려보며 이 신호를 찾는 건 불가능에 가까웠습니다.

개발자로서의 본능이 발동했습니다. "규칙이 명확하다면, 코드로 짤 수 있지 않을까?"

단순한 토이 프로젝트로 시작했지만, 며칠 밤을 새우며 차트 라이브러리와 씨름하고 투자 보조 지표를 객관적인 점수로 환산하는 과정이 꽤나 흥미로웠습니다. 이 글에서는 Next.js 16Vanilla Extract를 사용하여 S&P 500 주식 추천 서비스를 만든 경험을 공유하고자 합니다.

2. 핵심 기능과 UX

이 서비스는 복잡한 HTS(Home Trading System)를 대체하는 것이 목표가 아닙니다. 바쁜 현대인에게 **"오늘 주목해야 할 종목"**만 딱 집어 알려주는 것이 핵심입니다.

  • 오늘의 추천 (Daily Signals): 매일 장 마감 후 알고리즘이 분석한 '매수/매도' 신호를 보여줍니다.
  • 신뢰도 점수 (Confidence Score): 단순히 "사라/팔아라"가 아니라, 보조지표(MACD, RSI 등)를 종합하여 0~100점의 신뢰도를 제공합니다.
  • 직관적인 카드 UI: 모바일에서도 한눈에 신호와 차트 패턴을 확인할 수 있도록 카드 형태의 UI를 구성했습니다.

3. 기술 스택 선정 이유 (Tech Stack)

Next.js 16 (App Router)

서버 사이드 렌더링(SSR)과 정적 페이지 생성(SSG)의 장점을 모두 활용하기 위해 선택했습니다. 특히 주식 데이터는 장 마감 후 갱신되므로, 페이지를 미리 빌드해두거나 ISR(Incremental Static Regeneration)을 활용하면 사용자에게 엄청난 로딩 속도를 제공할 수 있습니다. 또한, Server Actions를 통해 DB 조작 로직을 백엔드 API 구축 없이 직관적으로 처리할 수 있었습니다.

Vanilla Extract (CSS)

Typescript 기반의 Zero-runtime CSS 라이브러리입니다.

  • 타입 안정성: 테마 변수나 스타일 속성에 오타가 있으면 빌드 타임에 잡아줍니다.
  • 성능: 런타임에 스타일을 주입하는 CSS-in-JS와 달리, 빌드 시점에 정적 CSS 파일을 생성하므로 초기 로딩 속도가 매우 빠릅니다.

Supabase & Vercel Cron

백엔드 구축에 힘을 빼기 싫어 Supabase를 선택했고, 매일 밤 데이터를 갱신하는 배치 작업은 Vercel Cron으로 해결했습니다. 별도의 배포 서버 없이 함수 하나만 작성하면 스케줄링이 가능하다는 점이 사이드 프로젝트에 최적화되어 있었습니다.

4. 개발 과정의 챌린지 (Deep Dive)

📈 "단순한 돌파 매매는 위험하다": 알고리즘 고도화 과정

처음에는 단순히 터틀 트레이딩의 원칙인 20일 신고가만 구현했습니다. 하지만 백테스팅 결과, 소위 '휩소(Whipsaw, 속임수 패턴)'에 걸려 손실이 나는 경우가 많았습니다. 신고가를 찍자마자 폭락하는 경우였죠.

이를 해결하기 위해 **3단계 점수 시스템(Tiered Scoring System)**을 도입했습니다.

  1. Tier 1 (추세): ADX와 MACD를 통해 현재 시장이 횡보장이 아닌 '추세장'인지 확인합니다.
  2. Tier 2 (진입): 거래량(Volume)과 RSI를 분석합니다. 거래량이 터지면서 상승해야 진짜 신호라고 판단합니다.
  3. Tier 3 (시장 리스크): 개별 종목이 좋아도 시장 전체(SPY)가 하락세거나 공포 지수(VIX)가 높으면 점수를 대폭 깎습니다.
// scoring.ts (실제 로직 요약)
// 1. 기본 신호 (터틀)
if (close > high_20) baseSignal = "BUY";

// 2. 가중치 계산
let totalScore = 50;

// ADX가 25 이상이어야 강한 추세로 인정
if (adx > 25) totalScore += 15;

// 거래량이 평균의 1.5배 이상 터져줘야 신뢰
if (volumeRatio > 1.5) totalScore += 15;

// 시장이 공포 구간(VIX > 30)이면 묻지마 감점
if (vix > 30) totalScore -= 15;

이 로직을 추가한 후, "오르다 말 것 같은" 가짜 신호들을 꽤 많이 걸러낼 수 있었습니다. 개발자가 코드로 시장의 노이즈를 제어하려는 시도 자체가 꽤나 도전적인 과제였습니다.

🤖 광고 최적화와 레이아웃 시프트 (CLS) 해결

수익화를 위해 AdSense를 붙였는데, 광고 로딩 전후로 화면이 덜컥거리는 CLS(Cumulative Layout Shift) 문제가 심각했습니다. 사용자 경험을 해치는 주범이죠.

이를 해결하기 위해 광고 컨테이너에 min-height를 강제하고, 스켈레톤 UI를 적용했습니다. 데스크톱에서는 728x90, 모바일에서는 유동적 사이즈를 적용하되 미리 공간을 확보해두는 방식으로 최적화하여 쾌적한 UX를 유지했습니다.

5. 마치며

직접 만든 알고리즘이 "매수 추천"을 띄운 종목이 다음 날 실제로 오를 때의 쾌감은 짜릿합니다. 물론 투자의 책임은 본인에게 있지만, 감정에 휘둘리지 않는 **'냉철한 조수'**를 곁에 둔 든든함이 있습니다.

Next.js 16의 최신 기능을 마음껏 써보며 기술적으로도 성장했고, 주식 시장을 데이터 관점에서 바라보는 시야도 넓어진 프로젝트였습니다. 앞으로는 백테스팅 엔진을 더 고도화하여 '수익률 시뮬레이션' 기능도 추가해볼 계획입니다.

주식 투자에 관심이 있거나, Next.js로 데이터 시각화 프로젝트를 해보고 싶으신 분들에게 도움이 되었으면 좋겠습니다.

👉 S&P 500 추천 서비스 써보기