티스토리 뷰
FastAPI + React로 봇 관리 대시보드 만들기
터미널 로그를 뚫어져라 쳐다보는 것도 한계가 있었다. "지금 포지션이 뭐지?", "오늘 수익률이 얼마지?", "봇이 살아있긴 한 거야?" — 이런 질문에 매번 로그를 뒤져야 했다. 웹 대시보드를 만들기로 했다.
API 서버: FastAPI
FastAPI를 선택한 이유는 간단하다. Python이니까 봇 코드와 같은 언어로 작성할 수 있고, 비동기 지원이 기본이고, WebSocket도 된다. Swagger 문서가 자동으로 생성되는 것도 좋았다.
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI(title="CryptoBot API")
@app.get("/api/portfolio")
async def get_portfolio():
"""현재 포트폴리오 상태"""
positions = db.get_open_positions()
balance = trader.get_balance()
return {"balance": balance, "positions": positions}
@app.get("/api/trades")
async def get_trades(limit: int = 50):
"""최근 매매 내역"""
return db.get_recent_trades(limit)
@app.post("/api/bot/stop")
async def stop_bot():
"""봇 긴급 정지"""
scheduler.pause()
return {"status": "stopped"}
API 엔드포인트는 크게 4개 카테고리로 나눴다. 포트폴리오 조회, 매매 내역, 봇 상태/제어, 전략 파라미터 조회/수정. REST API로 기본 CRUD를 처리하고, 실시간 데이터는 WebSocket으로 밀어준다.
실시간 WebSocket
대시보드에서 가장 중요한 건 실시간성이다. 1분마다 갱신되는 봇 상태를 브라우저에서 바로 볼 수 있어야 한다.
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
try:
while True:
# 봇의 매 틱 결과를 실시간 전송
data = await tick_queue.get()
await websocket.send_json({
"type": "tick",
"timestamp": data["timestamp"],
"prices": data["prices"],
"signals": data["signals"],
"portfolio_value": data["total_value"]
})
except WebSocketDisconnect:
pass
봇의 메인 루프가 틱을 처리할 때마다 결과를 asyncio Queue에 넣고, WebSocket 핸들러가 이걸 꺼내서 클라이언트에 전송한다. 연결이 끊어져도 봇은 영향을 받지 않는 구조다.
React 대시보드
프론트엔드는 React + Recharts로 만들었다. 핵심 화면은 3개다.
- Overview — 총 자산, 일일 수익률, 봇 상태(실행중/정지), 현재 포지션 요약
- Trades — 매매 히스토리 테이블 + 필터(코인별, 기간별, 승/패)
- Settings — 전략 파라미터 수정, 봇 시작/정지, 코인 추가/제거
포트폴리오 가치 변화를 라인 차트로 보여주고, 코인별 비중을 파이 차트로 표시한다. 매매 히스토리는 수익이면 초록, 손실이면 빨강으로 색을 입혔다. 단순하지만 한눈에 상태를 파악할 수 있다.
봇 제어 패널
대시보드에서 제일 많이 쓰는 기능은 봇 제어다. 시작/정지 버튼, K값 슬라이더, 손절률 조정. 파라미터를 바꾸면 API를 통해 즉시 반영되고, 다음 틱부터 새 파라미터가 적용된다. 긴급 상황에서는 "전체 매도" 버튼으로 모든 포지션을 시장가 청산할 수 있다.
// 긴급 전체 매도
const handleEmergencySell = async () => {
if (!confirm('정말 모든 포지션을 매도하시겠습니까?')) return;
await fetch('/api/bot/emergency-sell', { method: 'POST' });
};
confirm 한 번 더 물어보는 게 별거 아닌 것 같지만, 새벽에 졸린 눈으로 대시보드를 열었을 때 실수로 누르는 걸 막아준다.
모바일 대응
코인은 24시간 돌아간다. 밖에서도 봇 상태를 확인해야 한다. CSS Grid + Flexbox로 반응형을 잡았다. 복잡한 차트는 모바일에서 숨기고, 핵심 수치(총 자산, 현재 포지션, 봇 상태)만 보여주는 모바일 뷰를 별도로 만들었다. 폰에서 봇을 정지시킬 수 있다는 것만으로도 심리적 안정감이 크다.
대시보드가 생기니까 봇 관리가 확 편해졌다. 하지만 실전 운영은 대시보드만으로 해결되지 않는 문제들이 있었다. 다음 글에서는 운영 중 터진 장애들과 리스크 관리, 그리고 코드 리팩토링 이야기를 한다.
👉 다음 글 보러가기
'CryptoBot' 카테고리의 다른 글
| 실전 투입하자마자 터진 버그 6개 — 테스트에서 못 잡는 것들 (0) | 2026.04.13 |
|---|---|
| 실전 운영에서 터진 것들 — 리스크 관리와 리팩토링 (0) | 2026.04.11 |
| 승률 22%에서 배운 것 — 멀티코인 + 전략 진화 (0) | 2026.04.09 |
| Claude Haiku가 월 640원에 매매를 도와준다 — AI 자동매매의 시작 (0) | 2026.04.05 |
| 코인 자동매매 봇, 처음부터 만들기 — Python 하나로 MVP 완성 (2) | 2026.04.05 |
- Total
- Today
- Yesterday
- 코인별전략배정
- 일일주간월간스케줄러
- 코드자체감사
- 일경계처리
- P0P4우선순위
- kafka connect
- Haiku4096토큰
- 5중검증
- 트레일링스탑버그
- 데모모드
- BOJ #JS
- LLM파라미터머지
- SlidingWindowTTL
- 데이터엔지니어링
- CDC
- 한달운영진단
- LLM비활성결정
- Kafka
- jdbc
- AnthropicCaching
- CryptoBot
- 수수료슬리피지
- DataFramebool
- Page_DownPage_DownPage_Down
- 메이저화이트리스트
- LLM비용오차
- LLM동적호출
- 비용80%절감
- Telegram알림
- 코인별손익분석
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
| 31 |