이틀 만에 자리표시자였던 코드가 매일 자동으로 도는 공개 사이트가 됐다
2주차 1~2일차, 10종목 AI 매매 로직부터 매일 자동 실행·대시보드 3종까지 만들어서 로드맵 2주차 목표를 완성한 기록.
한 줄 요약: 1주차 끝엔 “AAPL 1종목, AI 판단 한 번 성공”이 전부였는데, 이틀(2주차 1~2일차) 만에 10종목 전체가 매일 밤 자동으로 판단·기록되고, 그 결과를 그래프·히스토리로 보여주는 공개 사이트까지 완성했다.
이런 분께 도움돼요: 계획은 잘게 쪼갰는데 “그래서 하루에 얼마나 진도가 나가야 정상인지” 감이 안 잡히는 분, GitHub Actions 자동화를 처음 실전에 연결해보는 분, 차트 라이브러리 없이 그래프를 그려야 하는 분.
Before
세부계획엔 9단계가 있었고, 1주차 끝엔 1~3단계(API 키, 데이터 하나, AI 판단 하나)만 끝난 상태였다. scripts/trade.js는 “자동 실행 확인”이라는 문구만 매일 찍는 자리표시자였고, 대시보드 페이지는 아예 없었다.
어떻게 했나
1일차 — 자리표시자를 진짜 로직으로 (4단계)
만들기 전에 먼저 오픈소스로 이미 있는 게 있는지 조사부터 했다. TradingAgents·AI Hedge Fund 같은 멀티에이전트 프레임워크가 나왔지만, PRD에서 이미 “간단하게, 백테스트 없이”로 범위를 좁혀둔 것과 안 맞아서 직접 만들기로 판단했다. 큰 도구를 그냥 가져다 쓰는 게 항상 정답은 아니라는 걸 배운 지점이다.
그다음 4단계를 작은 단계 5개로 쪼갰다 — 공용 함수 → 10종목 반복 → 자산 계산 → JSON 저장 → 로컬 테스트. 한 단계 끝날 때마다 바로 실행해서 확인하고 다음으로 넘어갔다.
// 판단 결과를 종목의 현금·보유수량에 반영 (종목당 독립된 $1,000 예산)
function 자산_반영(portfolioEntry, 판단, 현재가) {
if (판단 === '매수' && portfolioEntry.상태 === '현금') {
const 수량 = Math.floor(portfolioEntry.현금 / 현재가);
if (수량 > 0) {
portfolioEntry.현금 -= 수량 * 현재가;
portfolioEntry.보유수량 = 수량;
portfolioEntry.상태 = '보유';
}
} else if (판단 === '매도' && portfolioEntry.상태 === '보유') {
portfolioEntry.현금 += portfolioEntry.보유수량 * 현재가;
portfolioEntry.보유수량 = 0;
portfolioEntry.상태 = '현금';
}
}
복사2일차 — 자동화 실전 연결 (5단계), 그리고 첫 실패
워크플로에 GitHub Secrets를 연결하고 수동 실행 버튼을 눌렀는데, 바로 실패했다.
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@anthropic-ai/sdk'
복사로그를 읽어보니 Secrets는 정상적으로 잘 들어갔는데(FINNHUB_API_KEY: ***로 잘 나옴), 워크플로에 npm install 하는 단계 자체가 아예 빠져 있었다. GitHub Actions 서버는 매번 깨끗한 상태로 시작해서 node_modules가 없다는 걸 놓쳤던 것. 한 줄 추가하고 다시 실행하니 성공했다.
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci # ← 이 한 줄이 빠져서 실패했었다
- run: node scripts/trade.js
env:
FINNHUB_API_KEY: ${{ secrets.FINNHUB_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
복사대시보드 3종 (6~8단계)
PRD에서 정한 화면 구성 3가지를 각각 작은 단계로 쪼개서 만들었다.
종목별 상태 표 — 10종목의 현금/보유 상태를 표로
수익률 그래프 — 라이브러리를 새로 설치하지 않고, SVG를 직접 계산해서 꺾은선을 그렸다. 점 하나짜리 선 하나 그리자고 차트 라이브러리를 설치하는 건 오히려 과했다.
const x = (i) => PAD.left + (i / (series.length - 1)) * (W - PAD.left - PAD.right);
const y = (v) => H - PAD.bottom - ((v - domainMin) / (domainMax - domainMin)) * (H - PAD.top - PAD.bottom);
복사매매 히스토리 — “언제·어떤 종목·왜”를 리스트로, 매수는 초록·매도는 빨강 배지로 구분
통합 테스트 (9단계) — 그리고 또 한 번 막힘
배포된 사이트를 직접 열어 확인하던 중, 로컬 커밋을 푸시하려는데 거부당했다. 원인은 그사이 GitHub Actions 야간 자동 실행이 원격에 새 커밋을 이미 만들어둔 것 — 내가 로컬에서 작업하는 동안 자동화가 조용히 지 할 일을 하고 있었던 거다. git fetch + merge로 충돌 없이 합쳐졌다.
After
data/trades.json이 매일 밤 실제 10종목 AI 판단으로 자동 갱신됨/dashboard에서 상태 표·수익률 그래프·매매 히스토리를 실시간으로 볼 수 있음https://kevin-one-murex.vercel.app/dashboard — 로그인 없이 누구나 바로 볼 수 있는 공개 주소
로드맵 2주차 목표(“작동하는 매매 판단 로직 + 대시보드 초안”)가 완성됨
배운 점 / 재사용 자산
작은 단계마다 바로 실행해서 확인 — 5단계씩 쪼개고 매번 실행해보니, 문제가 생겨도 어디서 생겼는지 바로 알 수 있었다.
자동화 로그는 에러 메시지를 그대로 읽으면 원인이 나온다 —
npm ci빠진 것도 로그 한 줄로 바로 잡았다.작업 중 원격이 먼저 바뀌어 있을 수 있다 — 자동화가 돌고 있는 프로젝트라면, 푸시 전에 항상
git fetch로 먼저 확인하는 습관이 필요하다.사이트 분리 : 지금은 학습보드와 같은 사이트 안의 대시보드를 사용중이고 조금 더 구체화된다면 사이트를 분리할 예정이다.
SVG 직접 그리기 패턴: 점 개수가 적고 단순한 꺾은선이면, 차트 라이브러리 없이 좌표 계산 몇 줄로 충분하다. 새 의존성을 늘리기 전에 “정말 라이브러리가 필요한가”부터 물어볼 것.