FastAPI 읽기전용 대시보드 구축기 | 토스 자동매매 개발기 #15

🌐 Read in English

💡 이번 Phase 5 요약

  • 목적: 거래·알림·시세 이력을 조회만 할 수 있는 읽기전용 웹 대시보드 구현
  • 핵심 포인트: DRY_RUN 등 안전장치 값을 원격 변경하는 기능은 의도적으로 배제, 제어 기능은 텔레그램 봇 항목으로 분리
  • 검증: FastAPI TestClient로 서버 없이 10개 테스트, 전체 88개 통과

Phase 0부터 Phase 4까지 오면서 봇이 알아서 사고 파는 흐름은 어느 정도 자리를 잡았다. 그런데 막상 돌려놓고 나니 “지금 뭐 하고 있나”를 확인하려면 로그 파일을 직접 열어봐야 했다. Phase 5는 이 문제를 풀기 위한 단계고, 그 중 첫 항목으로 웹 대시보드부터 만들었다.

원래 Phase 5는 텔레그램 봇 명령어 인터페이스와 웹 대시보드 두 가지로 계획했는데, 텔레그램 봇은 실행 중인 프로세스를 외부에서 제어해야 해서 설계가 까다롭다. 그래서 상대적으로 안전한 웹 대시보드를 먼저 진행하기로 했다.

왜 100% 읽기 전용으로 설계했나

대시보드는 Phase 3에서 쌓아온 trades, alerts, price_snapshots 테이블을 조회해서 보여주는 용도로만 한정했다. DRY_RUN 값이나 목표가처럼 안전장치와 관련된 값을 원격에서 바꾸는 기능은 일부러 넣지 않았다. 그런 제어 기능은 별도로, 훨씬 신중하게 설계해야 한다고 판단했기 때문이다.

FastAPI로 dashboard.py 구현하기

dashboard.py를 새로 만들어서 메인 페이지(요약 카드 + 최근 거래/알림 테이블)와 JSON API 4종을 제공했다.

  • GET /api/trades
  • GET /api/alerts
  • GET /api/price-snapshots/{symbol}
  • GET /health

화면은 별도 프론트엔드 프레임워크 없이 인라인 HTML/CSS로 직접 렌더링했다. 대시보드 관련 설정(호스트, 포트, 표시 개수)은 하드코딩하지 않고 config.py에 추가했는데, 호스트 기본값은 외부 노출을 막기 위해 127.0.0.1로 고정해뒀다.

# config.py 발췌 (실제 값 마스킹)
DASHBOARD_HOST = "127.0.0.1"
DASHBOARD_PORT = 8000
DASHBOARD_RECENT_LIMIT = 20

# dashboard.py 발췌
@app.get("/api/trades")
def get_trades(limit: int = DASHBOARD_RECENT_LIMIT):
    # 예시 종목코드 마스킹 처리
    return query_trades(symbol="005930", limit=limit)

서버 없이 검증하기 — TestClient

FastAPI의 TestClient를 이용하면 실제 서버를 띄우지 않고도 각 엔드포인트를 인메모리로 검증할 수 있다. 헬스체크, 빈 DB 상태, limit 파라미터, 최신순 정렬, 종목별 필터링까지 총 10개 테스트를 test_dashboard.py에 작성했다.

여기에 안전장치 회귀 방지 테스트도 하나 더 추가했다. 등록된 모든 라우트가 GET 메서드만 허용하는지 검사해서, 나중에 실수로라도 상태를 바꾸는 POST/PUT/DELETE 엔드포인트가 추가되면 테스트가 바로 실패하도록 고정한 것이다.

삽질 기록: starlette.testclient requires the httpx2 package

로컬에서 pytest를 돌리는데 이런 에러가 났다.

RuntimeError: The starlette.testclient module requires the httpx2 package

원인을 보니 FastAPI가 내부적으로 쓰는 starlette 최신 버전이 테스트 클라이언트 기능에 기존 httpx 대신 새로운 httpx2 패키지를 요구하도록 바뀌어 있었다. pip install httpx2 한 줄로 바로 해결됐고, requirements.txt에도 반영했다.

최종 결과

전체 pytest를 다시 돌리니 88개(기존 78개 + 신규 10개)가 전부 통과했고, 안전장치 값에는 변화가 없다는 것도 확인했다. python dashboard.py를 실제로 실행해서 브라우저로 화면까지 직접 확인했다.

다음 단계

Phase 5의 남은 항목은 텔레그램 봇 명령어 인터페이스(/status, /holdings, /pause 등)다. 실행 중인 감시 루프를 외부에서 제어해야 하니만큼, 안전장치와의 상호작용을 특히 신중하게 설계해야 할 것 같다.

FAQ

Q1. 대시보드에서 매매 설정을 직접 바꿀 수 있나요?

아니요. 이번 대시보드는 거래·알림·시세 이력을 조회만 하는 읽기전용으로 설계했습니다. DRY_RUN이나 목표가 등 안전장치 값을 변경하는 기능은 의도적으로 넣지 않았습니다.

Q2. 왜 텔레그램 봇보다 웹 대시보드를 먼저 만들었나요?

텔레그램 봇은 실행 중인 프로세스를 외부에서 제어해야 해서 설계 난이도와 위험도가 높습니다. 상대적으로 안전한 조회 기능부터 구현하는 쪽을 선택했습니다.

Q3. httpx2 에러는 왜 발생했나요?

FastAPI가 의존하는 starlette 최신 버전이 테스트 클라이언트 기능에 기존 httpx 대신 httpx2 패키지를 요구하도록 변경되면서 발생했습니다. httpx2를 설치하면 해결됩니다.

Q4. 안전장치 변경 방지는 어떻게 테스트로 보장하나요?

등록된 모든 라우트가 GET 메서드만 허용하는지 검사하는 테스트를 별도로 추가해, 상태를 바꾸는 엔드포인트가 실수로 추가되면 테스트가 즉시 실패하도록 고정했습니다.

👉 [다음 편 이어보기] Phase 5(2): 텔레그램 봇 명령어 인터페이스 (발행 예정)

“FastAPI 읽기전용 대시보드 구축기 | 토스 자동매매 개발기 #15”에 대한 1개의 생각

댓글 남기기