이 시리즈는 증시 자동화 구축기 8편의 후속입니다.
이전 글: 운영기 A-2 — 이벤트 파이프라인 옆에서 돌아가는 독립 파이프라인들
다음 글: 운영기 B-1 — 실적·경제지표 캘린더 구현: 데이터가 시간차로 들어올 때
일간 블로그와 무엇이 다른가
일간 블로그는 단순하다.
하루치 데이터를 Claude에 넘기고, Claude가 마크다운 한 편을 반환하면 끝이다.
API 호출 1회.
주간·월간·분기는 다르다.
데이터 범위가 7일·30일·90일로 커지고, 분석해야 할 관점도 늘어난다.
한 번의 Claude 호출로 모든 것을 처리하려 하면 두 가지 문제가 생긴다.
첫째, 프롬프트가 너무 길어진다.
7일치 뉴스와 지수 데이터를 그대로 넣으면 토큰 한계에 걸리거나, Claude가 중요한 부분을 흘려보낸다.
둘째, 출력 품질이 고르지 않다.
"오늘 시황 + 종목 분석 + 포트폴리오 현황 + 다음 주 전략"을 한 번에 요청하면 어떤 섹션은 깊고 어떤 섹션은 얕게 나온다.
해결은 단계별 Claude 호출이다.
관점을 나눠서 각각 요청하고, 결과를 조합해서 하나의 문서를 만든다.
주간 블로그
Claude 6단계 파이프라인
매주 일요일 09:10에 실행되며,
지난 7일의 데이터를 종합한다.
@Scheduled(cron = "0 10 9 * * SUN", zone = "Asia/Seoul")
public void generateWeeklyBlogNow() { ... }
6단계가 순차 실행된다.
| 단계 | 내용 | Claude 호출 |
|---|---|---|
| 1단계 | 주간 시장 흐름 요약 | 1회 |
| 2단계 | 보유 종목별 주간 뉴스·분석 요약 | 종목 수만큼 |
| 3단계 | 주간 실적·경제지표 이슈 정리 | 1회 |
| 4단계 | 포트폴리오 변동 및 다음 주 전략 | 1회 |
| 5단계 | 블로그 제목 생성 | 1회 |
| 6단계 | DALL-E 대표 이미지 생성 | 1회 |
각 단계는 이전 단계 결과를 컨텍스트로 포함한다.
1단계 시장 흐름 요약이 2단계 종목 분석의 배경이 되고, 1~3단계 결과가 4단계 전략 수립에 쓰인다.
Claude 호출 횟수가 많아지는 대신 각 단계의 집중도가 높아진다.
컨텍스트로 들어가는 데이터는 일간보다 훨씬 풍부하다.
- 7일치 ChatGPT 분석 결과 (종목별 BUY/HOLD/SELL 판단 이력)
- 7일치 AI 예측 적중률 통계
- 주간 S&P500·나스닥·다우 등락 요약
- 주간 Tier 1·2 경제지표 발표 결과 + Surprise 분류
- 주간 실적 발표 결과 (BEAT/MISS/INLINE)
- 포트폴리오 주간 수익률 변화
이 데이터를 단계별로 압축해서 Claude에 넘기면 토큰 한계 없이 깊이 있는 분석이 나온다.

[이미지 1 — 주간·월간·분기 파이프라인 달력 뷰]
주간 이슈 자동 발굴
주간 블로그 완료 후 자동 트리거
주간 블로그가 생성되면 즉시 WeeklyIssueDiscoveryService.discoverNow()가 호출된다.
스케줄이 따로 없다. 주간 블로그 완료가 트리거다.
목적은 이번 주에 시장에서 중요했던 이슈를 자동으로 발굴해서,
사용자가 심층 분석 블로그를 생성할 이슈를 고를 수 있게 준비하는 것이다.
발굴은 2단계로 나뉜다.
1단계 — 정량 필터 (자동)
숫자로 판단할 수 있는 조건을 먼저 걸러낸다.
시장 충격
├─ 주간 S&P500 등락 ±2% 이상
└─ 주간 나스닥 등락 ±3% 이상
뉴스 집중도
├─ 동일 market_theme 뉴스 5건 이상
├─ signal_score 5점 이상 뉴스 2건 이상
└─ NEGATIVE 감성 비율 60% 이상
거시경제 키워드
├─ FOMC / Fed / Powell 키워드 3건 이상
└─ CPI / PPI / 고용 키워드 3건 이상
이 필터를 통과한 항목이 Claude 평가 대상이 된다.
2단계 — Claude 중요도 평가
필터를 통과한 이슈를 Claude에 넘겨 점수화한다.
평가 기준:
포트폴리오 영향도 (1~5점)
시장 파급력 (1~5점)
다음 주 지속 여부 (+2점 보너스)
참신성 체크 (기존 이슈 중복 제거)
선정: 합산 상위 최대 5개 / 3개 미만이면 발굴 중단
선정된 이슈는 DB에 저장되고, Telegram으로 "N건 발굴됨" 알림이 온다.
이후 사용자가 프론트엔드 이슈 목록에서 원하는 이슈의 [블로그 생성] 버튼을 누르면 Claude 심층 분석 블로그가 생성된다.
자동 발굴이지만 선택은 사람이 하도록 구현했다.
완전 자동화보다 이 방식이 블로그 품질 관리에 더 적합하다고 판단했다.
월간 블로그
Claude 9단계 파이프라인
매달 말일 11:00에 실행된다.
@Scheduled(cron = "0 0 11 L * *", zone = "Asia/Seoul")
public void generateMonthlyBlogNow() { ... }
L은 cron에서 "해당 월의 마지막 날"을 의미한다.
별도로 말일 계산을 구현할 필요가 없다.
9단계 파이프라인이 순차 실행된다.
| 단계 | 내용 |
|---|---|
| 1단계 | 이달 시장 흐름 요약 |
| 2단계 | 이달 매매 기록 분석 |
| 3단계 | 수익 현황 (종목별 손익, 전월 대비) |
| 4단계 | AI 예측 월간 적중률 분석 |
| 5단계 | 이달 실수와 개선 포인트 |
| 6단계 | 다음 달 전략 |
| 7단계 | 블로그 제목 생성 |
| 8단계 | 전체 내용 DB 저장 |
| 9단계 | DALL-E 대표 이미지 생성 |
주간(6단계)보다 3단계가 더 많다.
추가된 것은 "실수와 반성", "다음 달 전략"처럼 회고 관점의 섹션이다.
한 달치 데이터를 요약하다 보면 자연스럽게 더 많은 관점이 필요해진다.
이미지 생성(9단계)이 실패해도 텍스트 초안은 DB에 저장된 상태를 유지한다.
9단계 실패가 전체를 롤백하지 않는다.

[이미지 2 — Claude 단계별 호출 횟수 비교]
분기 AI 비중 제안
90일 데이터와 JSON 파싱 오류
매 분기 말일(3/6/9/12월 마지막 날) 11:00에 실행된다.
@Scheduled(cron = "0 0 11 L 3,6,9,12 *", zone = "Asia/Seoul")
cron에서 L 3,6,9,12는 "3월, 6월, 9월, 12월의 마지막 날"을 의미한다.
컨텍스트 구성
Claude에 넘기는 데이터가 가장 방대하다.
90일 뉴스 sentiment 집계 (종목별 POS/NEG/NEU 비율)
최근 실적 발표 결과 (BEAT/MISS/INLINE)
30일 Tier 1·2 경제지표 발표 결과
현재 종목별 목표 비중
섹터 집중도 규칙 (40% 초과 억제)
Claude에 요청하는 것은 간단하다.
현재 포트폴리오의 종목별 비중을 얼마나 늘리거나 줄여야 하는지 delta(±%)로 알려달라는 것이다.
// Claude 응답 예시 (기대 형식)
{
"NVDA": { "delta": 3.0, "reason": "AI 수요 지속..." },
"TSLA": { "delta": -2.0, "reason": "거시 압력..." },
"AAPL": { "delta": 0.0, "reason": "중립 유지..." }
}
조건이 두 가지 붙는다. 모든 delta의 합계는 0이어야 한다(비중 재조정이므로).
특정 섹터 집중도가 40%를 넘으면 해당 섹터 종목의 delta를 줄이도록 프롬프트에 명시했다.
운영에서 만난 파싱 오류 (ISSUE-011)
처음 배포했을 때 파이프라인이 500 오류로 즉시 죽었다.
Unexpected character ('+') in numeric value: JSON spec does not allow numbers to have plus signs
Claude가 양수 delta를 3.0이 아닌 +3.0으로 반환했다.
JSON 표준(RFC 8259)은 숫자 앞에 + 기호를 허용하지 않는다.
Jackson의 기본 파서도 마찬가지다.
해결은 두 단계였다.
// 1. JSON 추출 직후 + 기호 제거
String json = extractJson(rawResponse);
json = json.replaceAll(":\\s*\\+([0-9])", ": $1");
// 2. 프롬프트 예시 수정
// 변경 전: "(예: +3.0, -2.0, 0.0)"
// 변경 후: "(예: 3.0, -2.0, 0.0) — 양수는 부호 없이, 음수만 - 기호 사용"
정규식으로 파싱 직전에 정제하고, 프롬프트 자체도 수정해서 근본 원인을 차단했다.
4편에서 다룬 AI 응답 파싱 정제 패턴과 동일한 원칙이다.
주간 이슈 자동 발굴 흐름
주간 블로그 생성 완료
↓
WeeklyIssueDiscoveryService.discoverNow() 자동 호출
↓
1단계: 정량 필터 (DB 조회만, Claude 미사용)
시장 충격 조건 확인
뉴스 집중도 조건 확인
거시경제 키워드 조건 확인
↓
2단계: Claude 중요도 평가 (필터 통과 항목만)
포트폴리오 영향도 + 시장 파급력 + 지속성 + 참신성
합산 상위 5개 선정 (3개 미만이면 중단)
↓
Telegram: "이번 주 이슈 N건 발굴됨"
↓
사용자가 프론트엔드에서 [블로그 생성] 버튼 클릭
↓
WeeklyIssueBlogService: Claude 심층 분석 블로그 생성
정량 필터를 먼저 거르는 이유는 비용 때문이다.
Claude 평가는 필터를 통과한 항목만 받는다. 아무 이슈도 없는 평온한 주에는 Claude 호출 자체가 발생하지 않는다.

[이미지 3 — 주간 이슈 발굴 플로우]
왜 단계별 호출인가
월간 블로그를 처음 만들 때 한 번의 거대한 프롬프트로 모든 것을 요청했다.
결과가 두 가지 문제를 냈다.
첫째, 어떤 섹션은 상세하고 어떤 섹션은 한두 문장으로 끝났다.
Claude가 긴 프롬프트에서 중요도를 스스로 판단해버렸다.
둘째, 재생성이 어려웠다.
매매 기록 섹션만 다시 쓰고 싶어도 전체 프롬프트를 다시 실행해야 했다.
단계별로 나누면 두 문제가 모두 해결된다.
각 단계는 그 섹션만 집중해서 쓴다.
특정 단계만 실패하면 그 단계만 재실행하면 된다.
실행 시간이 길어지는 단점이 있지만,
월간 블로그는 한 달에 한 번이라 허용 가능한 비용이다.
정리
| 파이프라인 | 실행 주기 | Claude 단계 | 데이터 범위 | 특이사항 |
|---|---|---|---|---|
| 주간 블로그 | 매주 일요일 | 6단계 | 7일 | 완료 후 이슈 발굴 자동 트리거 |
| 주간 이슈 발굴 | 주간 블로그 직후 | 정량 필터 + 1회 | 7일 | 3건 미만이면 중단 |
| 월간 블로그 | 매월 말일 | 9단계 | 30일 | 이미지 실패해도 텍스트 유지 |
| AI 비중 제안 | 분기 말일 | 1회 + 파싱 | 90일 | + 기호 JSON 파싱 오류 처리 필요 |
그룹 A 편(A-1, A-2, A-3)에서 파이프라인 진화 과정을 모두 다뤘다.
다음 그룹 B에서는 파이프라인이 다루는 도메인들을 살펴본다.
실적·경제지표 데이터를 어떻게 설계했는지,
시간차 데이터가 들어올 때 DB 스키마를 어떻게 잡았는지부터 시작한다.