금융 데이터를 설명 가능한 신호로|PLUTUS MACRO 수집·판단·배포 개발 사례
기준일: 2026년 10월 16일 · 개발 패키지: v1.3.0. 이 글은 소스 코드, 개발 환경의 실제 수집 결과와 검증 기록을 바탕으로 작성했습니다. 최신 패키지의 운영 서버 적용 및 운영 화면 검증은 별도이며, 이 글이 배포 완료를 의미하지는 않습니다.
PLUTUS MACRO의 개발 과제는 외부 금융 데이터를 가져오는 것에서 끝나지 않았습니다. 공급자 장애와 단위 차이를 다루고, 같은 자료에서 점수와 설명이 일관되게 나오도록 만들며, 다른 서비스가 운영 중인 Ubuntu 서버에 변경 범위를 제한해 배치해야 했습니다. 이 사례는 그 요구를 실제 수집 서버와 설명 가능한 규칙 기반 대시보드로 연결한 과정입니다.
1. 설계 목표와 기술 선택
| 계층 | 선택 | 선택 이유와 한계 |
|---|---|---|
| 수집·API | Python 3.12 표준 라이브러리 | 배포 의존성 축소. 전문 웹 프레임워크의 운영 기능은 별도 구현 필요 |
| 저장 | SQLite WAL | 단일 서버의 시계열·상태·계정 보존. 다중 서버 확장에는 재설계 필요 |
| 화면 | React 19 · TypeScript · Vite | 판단 로직을 순수 함수로 분리하고 상태·근거 표시 |
| 시각화 | SVG 기반 차트 | 게이지·시계열·지표 비교를 코드로 구현 |
| 운영 | Nginx · systemd | TLS 종단, 내부 API, 예약 수집과 백업 분리 |
판단 과정에는 학습된 AI 모델을 넣지 않았습니다. 점수와 경고는 소스에 공개된 결정 규칙으로 계산합니다. 따라서 생성형 AI의 시장 예측이나 수익률 최적화 모델로 소개할 수 없습니다.
2. 데이터 흐름과 책임 분리
- 수집: systemd 타이머가 수집 프로세스를 실행하고 공급자별 요청을 제한된 동시성으로 처리합니다.
- 정규화: 날짜·단위·범위를 검증하고 지표·관측일·출처 기준으로 저장합니다.
- 보존: 마지막 정상값, 공급자 상태, 원시 응답과 수정 관측을 남깁니다.
- 제공: 내부 API가 저장된 자료와 상태를 반환합니다.
- 해석: 화면의 순수 계산 모듈이 기술 지표·점수·경고·체크 항목을 생성합니다.
브라우저 새로고침은 외부 데이터 수집을 직접 실행하지 않습니다. 조회 트래픽과 공급자 호출을 분리해 사용자 수가 곧 수집 요청 수가 되는 구조를 피했습니다.
3. 수집 어댑터와 실패를 다루는 방식
HTTP 요청에는 12초 타임아웃, 일시적 오류 재시도, 16MiB 응답 상한을 적용하고 최대 4개 작업으로 수집 동시성을 제한했습니다. 프로세스 잠금으로 중복 수집을 막습니다. 공급자 오류가 발생하면 마지막 정상 관측을 보존하고 마지막 성공 시각과 확인 시각을 별도로 기록합니다.
| 발생한 문제 | 처리 | 해결로 간주하지 않은 부분 |
|---|---|---|
| CNN HTTP 418 | 파싱 보강·보조 재게시 출처 분리 | 차단 해제 및 원본 일치 검증 미완료 |
| 국내 자금 자료 누락 | FreeSIS 공개 JSON 직접 조회, 네이버 보조 경로 | 공개 응답 형식의 장기 안정성 보장 없음 |
| 수출 자료 부재 | 월 전체와 최근 잠정 조회를 별도 구현 | 두 기간의 범위·조업일수 차이를 자동 무시하지 않음 |
| 외부 80번 포트 차단 | HTTPS 인증 절차를 서버 조건에 맞게 분리 | 443 리스너만으로 HTTP-01 문제가 해결되지는 않음 |
4. 데이터 계약: 날짜·출처·단위가 기능이다
관측은 지표 ID, 관측 날짜, 출처를 기준으로 저장하며 공급자 우선순위와 수정 자료를 다룹니다. 원시 응답은 압축 보존하고 SHA-256 식별값을 남깁니다. 이는 오류 조사와 재현의 근거이며 외부 원자료의 영구 불변성을 보장하는 장치는 아닙니다.
| 자료 | 정규화·검증 포인트 |
|---|---|
| 예탁금·신용잔고 | 공급자별 억 원 단위를 확인하고 조 원으로 정규화 |
| 반대매매 | 미수금 반대매매 범위와 공표 비중을 별도로 유지 |
| 신용공여 합산 | 신용융자+신용대주 파생값임을 명시 |
| 일평균 수출입 | 총액 단위와 공식 조업일수를 함께 검증; 총액 증가율과 일평균 증가율 분리 |
| 순유동성 | 연준 자산·재무부 계정·역레포의 단위와 관측 시점을 맞춘 후 계산 |
결측은 0이 아닙니다. 지연 자료도 최신값으로 포장하지 않습니다. 동일 날짜의 신용잔고와 예탁금이 없으면 비율의 해석을 제한합니다. 발표일·조회일·관측일도 같은 개념으로 취급하지 않습니다.
5. 기술 지표와 다이버전스의 시간 문제
RSI는 Wilder 14, MACD는 EMA 12·26과 신호선 9를 사용합니다. 이동평균선 20·50·100·200일은 가격의 위·아래뿐 아니라 기울기를 함께 판정합니다.
일반형 다이버전스는 최근 90관측일의 종가 피벗을 비교합니다. 좌우 2개 봉, 피벗 간격 5~60관측일, 가격 0.3%와 RSI 3점의 반대 움직임을 조건으로 사용합니다. 두 번째 피벗의 오른쪽 봉이 없으면 ‘형성 중’으로 분리합니다. 피벗 발생일과 신호 확인일을 구분하는 것이 뒤늦게 알게 된 정보를 과거에 알고 있었던 것처럼 표시하지 않기 위한 핵심입니다.
확인 후 15관측일이 지나면 만료시키고 추가 신고점·신저점에서 RSI가 추세를 확인하면 무효화합니다. 고가·저가가 아닌 종가 기반이며 임계값은 백테스트로 최적화한 결과가 아닙니다.
6. 설명과 점수를 같은 판단 체계로
초기 구현은 이동평균선 위치로 높은 점수를 주면서 RSI·MACD 경고는 별도 목록에 표시했습니다. 이를 매크로 기초 점수, 기술 반영 점수, 위험 상한, 최종 결과의 계산 내역으로 바꾸었습니다. 동일 상태가 점수와 문구에서 다른 의미를 갖지 않도록 개별 지표의 주의·위험 조건을 점수 상한에 연결했습니다.
| 규칙 계층 | 대표 조건 | 처리 |
|---|---|---|
| 영역 가중치 | 심리25·유동성30·금리신용20·추세15·실적10 | 사용 가능한 영역을 재정규화 |
| 데이터 적합성 | 결측·오래된 자료·참고 전용 공급자 | 점수 제외; 커버리지50% 미만 종합 미표시 |
| 하이일드 | 수준과5·10·20관측일 확대 폭 | 더 위험한 조건 우선 |
| 거시 위험 상한 | VIX30 이상 또는 하이일드 위험 | 최종44점 상한 |
| 심각한 위험 상한 | VIX40 이상 또는 하이일드 심각 | 최종29점 상한 |
| 기술적 경고 | 2개 이상 확인된 하락 다이버전스 | 최종54점 상한 |
상한은 누적 감점과 다릅니다. 여러 조건이 겹쳐도 가장 제한적인 최댓값을 적용합니다. 임계값은 공개된 운영 정책이며 시장 상승 확률을 뜻하지 않습니다. 신호 개수의 단순 투표도 사용하지 않습니다.
7. 바닥 탐색을 단일 매수 신호로 만들지 않기
레버리지 조건은 결측 대기, 정상, 청산 압력, 후보, 위험 차단의 상태로 분리했습니다. 과매도, 신용잔고 급감, 반대매매 급증을 함께 확인한 뒤 가격·RSI·MACD의 안정과 거시 위험을 추가 검사합니다.
반대매매 급증은 최근 3관측일 최댓값을 이전 최대 60관측일의 평균 2배 또는 95백분위와 비교하며 최소 20개 기준 관측을 요구합니다. RSI 최근5개 30 이하와 신용잔고5관측일 −3% 이하 조건을 함께 사용합니다. VIX30 이상이나 심한 신용 위험은 진입 후보보다 우선합니다. 이 파생 신호는 종합점수를 올리지 않습니다.
개발 검증에서는 과매도와 반대매매 급증이 있어도 신용잔고 감소 폭과 가격 안정 조건이 충족되지 않아 후보를 강제로 만들지 않는 결과를 확인했습니다. 이는 규칙 동작 확인이며 투자 성과 검증이 아닙니다.
8. 계정과 서비스 경계
이메일을 계정 ID로 사용하는 가입·로그인을 구현했습니다. 비밀번호는 무작위 salt와 scrypt로 저장하고 세션 토큰은 해시로 보존합니다. 쿠키는 Secure·HttpOnly·SameSite=Lax와 만료를 적용하며 요청 Origin 검사와 로그인 시도 제한을 둡니다. 수동 데이터 수정 권한은 일반 회원 세션과 별도로 분리합니다.
이메일 소유 확인, 가입 확인 메일, 비밀번호 재설정 메일은 구현하지 않았습니다. 로그인 제한은 프로세스 단위이며 다중 서버용 공유 제한기가 아닙니다. 현재 범위를 완성된 기업용 IAM이나 포괄적인 보안 검증 완료로 표현하지 않습니다.
9. 기존 서버와 공존하는 배포
애플리케이션은 전용 계정·저장소·systemd 서비스를 사용하고 API는 루프백 8788에서 수신합니다. Nginx가 전용 도메인의 TLS 요청을 전달합니다. 정기 수집은 한국 시간 하루 5회, 백업은 매일 수행하도록 구성했습니다.
업데이트 패키지는 서버에서 apt·pip·npm 설치를 실행하지 않습니다. 전용 데이터와 설정을 백업하고 릴리스 경로를 전환한 뒤 macro 서비스만 재시작합니다. 내부 health와 미인증 API 거부를 검사하고 전용 도메인 설정 변경 후 nginx -t를 거쳐 공용 Nginx를 reload합니다. 오류 시 코드·설정 복귀 경로를 준비했습니다.
API와 수집 서비스에는 CPU·메모리 제한을 설정했습니다. 다만 Nginx와 디스크 등 공유 자원이 있으므로 ‘기존 서비스에 영향이 전혀 없다’고 보장할 수는 없습니다. 실제 서버의 자원 여유, 도메인·인증서, 복귀 동작은 대상 환경에서 확인해야 합니다.
10. 개발 이력과 검증 범위
| 단계 | 요구와 문제 | 구현 변화 |
|---|---|---|
| v1.0 | 화면 시제품을 실제 서비스로 전환 | Python 수집 서버, SQLite, API, React 화면, 예약 수집·백업·전용 서비스 구성 |
| v1.1 | 수집 누락과 단순 수치 판단 개선 | 수출입·예탁금·신용잔고 수집 보강, 하이일드 변화 속도, 금리차 해석, 이메일 계정과 안전한 업데이트 |
| v1.2 | 점수와 경고의 불일치 해소 | RSI 다이버전스, 단계별 종합 계산과 위험 상한, 수출 상관계수·적정 코스피 화면 제거 |
| v1.3 | 읽기 쉬운 판단과 개인 레버리지 점검 | 공포·탐욕 게이지·추이, 기술 지표 색상, FreeSIS 직접 수집, 바닥 탐색 조건, 매매 가이드·달걀모형 |
| 검증 항목 | 결과와 범위 |
|---|---|
| Python 백엔드 | 18개 테스트 통과 |
| 금융 규칙 | TypeScript 회귀 검증 통과 |
| 정적 검사·번들 | TypeScript 검사 및 Vite 빌드 통과 |
| 실제 수집 | FreeSIS·관세청 등 개발 환경의 공급자 응답 확인 |
| 렌더링 | 실제 데이터 기반 React 서버 렌더링 및 구조 검사 |
| 미완료 | 전체 브라우저 시각 검사, 최신 패키지의 운영 서버 적용·통합 검증 |
버전 표는 기능 변화의 기록이며 서로 다른 날짜의 운영 릴리스 기록은 아닙니다. 빌드 성공, 실제 수집 성공, 운영 배포 성공은 별개의 검증 단계로 관리합니다.
11. 다음 개발 과제
- 공급자 응답 변경 감지와 스키마 회귀 자료 확대
- CNN 원본 대조 및 보조 출처 신뢰도 검증
- 이메일 소유 확인·계정 복구와 운영 인증 강화
- 실제 브라우저 접근성·모바일 화면 검사
- 시점별 데이터로 판단 규칙 백테스트 및 오류 비용 평가
- 운영 서버 적용 후 서비스·백업·복귀 절차 검증
이 항목들은 향후 과제이며 현재 제공 기능으로 계산하지 않습니다. 핵심 성과는 지표 수를 늘린 데 있지 않고, 출처·시간·누락·판단 근거를 사용자에게 드러내는 구조를 만든 데 있습니다.
문서 범위: 구현 사례 소개이며 보안 인증, 투자 성과 보증 또는 특정 금융상품 권유가 아닙니다. 외부 공개 데이터의 이용 조건과 공급자 변경은 운영 과정에서 지속 확인해야 합니다.