저희 사륜구동 팀의 주제는, '블록 기반 사용자 전략 자동 매매 서비스'입니다.
사용자가 보조지표와 지표 블록(EMA, RSI, MACD, 거래량 등)을 조합해 자신만의 매매 전략을 구성하고 이를 실시간으로 실행할 수 있도록 설계했습니다.

저희 시스템 아키텍처를 보면 위와 같이 구성되어있습니다.
| 기술 | 이유 |
|---|---|
| Spring Boot | 유지보수 용이 |
| MongoDB | 주문에 관련된 반정형 JSON 전략 구조에 적합 |
| MariaDB | 사용자/주문 데이터의 정형화된 관리 |
| Kafka | 실시간 스트리밍 |
| ArgoCD + K8s | 전략별 pod 배포 자동화 |
| WebClient | 논블로킹 방식의 OpenAPI 호출 |
| Redis | 중앙에서 토큰 관리 |
| Flask | 전략 실행, 가벼운 파이썬 서버 |
저희는 사용자 전략마다 pod를 1개씩 띄웁니다. 그렇게 생각한 이유는, kafka에서 지표, 보조지표, 시세데이터들이 뿌려질 때마다 사용자들의 전략이 실행되어야합니다.
그리고, 그 전략에 알맞는 상황일 경우 매매를 수행하고 전략을 꺼야되는데, 실시간 성을 살리고 전략끼리의 독립성을 유지하기 위해서 pod를 여러개를 띄우는 구조로 정했습니다.
market module에서 시세데이터를 받아서 모든 보조지표와 지표를 계산해서 pod들에게 뿌려줘야합니다. 따라서, 여러 pod들에게 빠르게 실시간으로 전달해야 됐기 떄문에 kafka를 사용했습니다.
저희는 토픽을 설계할 때,
[주식 ticker].[봉단위]로 이름 지어서 토픽을 발행 하고 있습니다.
따라서, pod들은 자신에 맞는 ticker topic만 consume하는 구조로 설계되어있습니다
{
"strategy_name": "전략 이름",
"version": 1,
"owner_id": "user_123",
"meta": {
"universe": ["005930"], // 종목정보
"enabled": true // 실행 여부
},
"buy": { // 매수 블록
"node": {
"type": "GROUP",
"logic": "ALL",
"label": "BUY ROOT: 볼린저 밴드 상단 돌파",
"children": [
{
"type": "CROSS",
"label": "A1: close(15m) CROSS UP BB.upper(20, 2, 15m)",
"direction": "UP",
"left": {
"kind": "PRICE",
"field": "close",
"timeframe": "15m"
},
"right": {
"kind": "INDICATOR",
"name": "BOLLINGER_BANDS",
"args": { "period": 20, "stddev": 2 },
"subfield": "upper",
"timeframe": "15m"
}
}
]
}
}
}
저희의 전략 json은 다양한 조합으로 구성됩니다. 사용자의 요청에 따라 다양한 형태의 json으로 오기 때문에, rdb에 이것을 저장하기에는, key마다 쪼개야 하는 것도 많고 복잡하기 때문에, 연산량도 너무 많을 것이라고 생각했습니다.
따라서, mongodb에 이것을 저장해서 관리하게 된다면, 유저가 다양한 조합을 주더라도 그대로 저장할 수 있을 것이라고 생각해서 mongodb를 사용해서 저장하기로 결정했습니다.
저희 서비스에서는, Redis를 통해 중앙에서 토큰을 관리합니다. 이를 통해, 여러 서비스가 동일한 토큰을 공유하고 만료 시점을 일괄적으로 갱신할 수 있습니다.
특히 백엔드에서 redis를 사용할 때, read와 write를 나눠서, 모듈마다 쓰기 제한을 하도록 구성했습니다.




그리고 auth 서버에서만 redis에 write 가능하도록 구성해서 책임을 분리했습니다.

