가격이 아니라 이벤트를 팔자 — monticker 설계 철학
프로젝트를 시작한 동기
주식 앱을 처음 열었을 때 보이는 화면은 대부분 동일하다.
1
삼성전자 73,200 +1.4% [캔들 차트] [뉴스 목록]
숫자가 움직이는 건 알겠는데, 왜 움직이는지 한눈에 들어오지 않는다. 뉴스 탭을 눌러야 하고, 거래량 탭을 따로 눌러야 하고, 공시 탭도 따로 있다. 정보가 파편화되어 있다.
실제로 트레이더들이 “이 차트 어떻게 봐야 해?”라는 질문에 시간 축 위에서 사건을 짚어가며 설명한다는 사실에서 monticker의 핵심 아이디어가 나왔다.
가격 차트 위에 이벤트를 직접 올리면 어떨까?
이벤트 중심(Event-Centric) UI란
일반적인 주식 앱:
1
2
3
4
10:00 | 70,000 ─────────────────────────
10:05 | 70,200
10:10 | 72,500 ← 왜 올랐지?
10:15 | 72,300
monticker:
1
2
3
4
10:10 ▲ PRICE_SPIKE +3.2%
├── 거래량: 평균의 4.8×
├── 뉴스: "HBM 공급 확대 기대감"
└── 공시: 없음
가격 변동의 원인을 타임라인에 직접 표시한다. 사용자가 차트와 뉴스를 오가며 수동으로 연결할 필요가 없다.
이 아이디어를 기술로 구현하면 다음과 같은 파이프라인이 된다.
1
2
3
4
5
6
7
External data sources
→ workers (price + news + disclosure collector)
→ Redis (latest price) + TimescaleDB (candles)
→ Event Detector (EMA 기반 이상 탐지)
→ stock_events (이벤트 테이블)
→ REST / WebSocket API
→ 차트 타임라인 오버레이 (web / mobile)
“이벤트”를 어떻게 정의했는가
monticker에서 이벤트는 5가지 유형으로 분류된다.
| 유형 | 예시 | 탐지 방법 |
|---|---|---|
PRICE_SPIKE | 5분 내 3% 이상 급등 | EMA 기반 변화율 |
VOLUME_SURGE | 평균 거래량의 3× 이상 | EMA 기반 비율 |
NEWS_POSITIVE | 긍정 뉴스 발행 | 네이버 뉴스 + 감성 분석 |
DISCLOSURE | 공급 계약, 실적 발표 | DART API |
PATTERN_DETECTED | 이중 바닥, 헤드앤숄더 | ZigZag 패턴 매칭 |
이 이벤트들이 하나의 stock_events 테이블에 모이고, 타임라인 API는 주어진 기간의 이벤트 목록을 차트 라이브러리가 소비할 수 있는 형식으로 반환한다.
제품이 확장된 방향
처음에는 순수하게 “왜 가격이 움직였는지 보여주는 앱”을 목표로 했다. 그런데 개발 과정에서 자연스럽게 이어진 질문들이 있었다.
“이 패턴이 반복되는지 확인하고 싶다” → Quant Lab (전략 백테스트)
“주문을 넣으면 어떻게 체결되는지 배우고 싶다” → 모의투자 + CLOB 체결 엔진
“내가 충동적으로 주문을 많이 넣는 것 같다” → Investment Wallet + 감정 태그
“내 전략이 어떤 시장에서 약한지 알고 싶다” → Quant Analytics (국면 감지 + 포트폴리오 최적화)
각 확장이 “가격이 왜 움직이는가”라는 원래 질문과 연결되어 있다는 점이 중요하다. 그냥 기능을 추가한 게 아니라, 투자자가 시장을 이해하는 사고 과정을 따라서 제품이 깊어진 것이다.
이 프로젝트에서 다루는 기술 스택
이후 시리즈에서 상세히 다룰 내용의 전체 그림이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌─── 수집 ──────────────────────────────┐
│ Go Market Gateway → Kafka │
│ (goroutine-per-stock) market.ticks │
└────────────────────────────────────────┘
↓
┌─── 처리 ──────────────────────────────┐
│ Kotlin Worker (Spring Boot) │
│ ├── CandleAggregator → TimescaleDB │
│ ├── EventDetector → stock_events │
│ └── RedisTickWriter → Redis │
└────────────────────────────────────────┘
↓
┌─── 서빙 ──────────────────────────────┐
│ Spring Boot API → REST / WS │
│ Netty Broadcast → WebSocket 클라이언트 │
└────────────────────────────────────────┘
↓
┌─── 클라이언트 ─────────────────────────┐
│ Next.js 15 (App Router) │
│ Expo React Native (mobile) │
└────────────────────────────────────────┘
| 레이어 | 기술 | 이유 |
|---|---|---|
| 수집 | Go | goroutine의 가벼운 동시성 |
| 메시지 버스 | Kafka | 수집-처리 분리, 순서 보장 |
| 시계열 저장 | TimescaleDB | PostgreSQL 호환 + Hypertable |
| 캐시 | Redis | 최신 시세 서빙, 알람 쿨다운 |
| API 서버 | Kotlin/Spring Boot | 도메인 모델링, 생태계 |
| 브로드캐스트 | Netty | 스레드 효율적인 WebSocket |
| 프론트엔드 | Next.js 15 | SSR + App Router |
이 시리즈를 읽는 방법
monticker 시리즈는 총 6개 주제로 구성된다.
| 시리즈 | 주제 | 편수 |
|---|---|---|
| 1. 아키텍처 설계 | 제품 철학·기술 선택 | 3 |
| 2. 실시간 파이프라인 | Go·Kafka·Netty | 4 |
| 3. 체결 엔진 | CLOB·리스크 게이트 | 2 |
| 4. 이벤트 소싱 | 원장·감정 태그 | 2 |
| 5. Quant Lab | 룰 엔진·백테스트 | 3 |
| 6. Quant Analytics | 최적화·패턴·국면 | 5 |
| 보너스 | 테스트·관측가능성 | 3 |
다음 편에서는 마이크로서비스가 아닌 모듈식 모놀리스를 선택한 이유를 다룬다.
댓글
아직 댓글이 없습니다