티스토리 뷰

사람이 안 봐도 되는 봇을 만들자

6편에서 하루 만에 hotfix 6개를 쏟아낸 뒤, 확신이 생겼다. 이대로는 안 된다. 내가 24시간 로그를 보고 있을 수는 없다. 봇이 스스로 검증하고, 문제가 있으면 알아서 멈추고, 정기적으로 상태를 점검하는 시스템이 필요했다.

매매 5중 검증 — 믿을 수 있는 거래

6편의 버그들을 겪고 나서 매매 과정 전체에 검증 레이어를 쌓았다.

# 1. 가격 검증 — 0이나 직전 대비 20% 급변 시 스킵
if price <= 0 or abs(price - last_price) / last_price > 0.2:
    alert("비정상 가격 감지")
    return

# 2. 주문 체결 검증 — success=True여도 실제 잔고 확인
result = trader.buy_market(coin, amount)
actual = trader.get_balance_coin(coin)
if actual == 0:
    alert("매수 체결 실패: 잔고 0")

# 3. 잔고 일관성 — 매매 전후 차이가 예상과 5% 이상 다르면 경고
# 4. DB 쓰기 검증 — INSERT 후 SELECT로 존재 확인
# 5. 중복 매수 방지 — 이미 보유 중인 코인 재매수 차단

이 5단계가 전부 통과해야 거래가 완료된다. 하나라도 실패하면 Slack 알림 + 거래 중단. 과하다 싶을 수 있지만, 돈이 오가는 시스템에서 검증은 과할수록 좋다.

스케줄러 체계 — 일일/주간/월간

1분마다 틱을 도는 메인 루프 외에, 세 가지 정기 작업을 추가했다.

일일 헬스체크 (매일 06:00)

  • DB 거래 기록과 업비트 실제 체결 내역 대조 — 불일치 시 알림
  • 미체결 주문 정리
  • 뉴스 수집 (RSS)

주간 리포트 (매주 월요일)

  • 전략별 주간 승률, 평균 수익률 랭킹
  • DB 최적화 (VACUUM, 오래된 스냅샷 정리)
  • LLM 파라미터 추이 분석

월간 감사 (매월 1일)

  • 전체 거래 1:1 대조 감사
  • DB 전체 백업
  • LLM API 비용 정산

일일 리포트도 개선했다. 기존에는 단일 코인 KRW 잔고만 봤는데, 멀티코인 대응 + 보유 코인 시가 반영으로 바꿨다. 미실현 손익이 항상 0이었던 것도 이때 잡았다.

LLM 호출 최적화 — 4시간에서 동적으로

처음에는 LLM을 4시간마다 호출했다. 너무 느렸다. 2시간으로 줄이고, 다시 30분으로 줄였다. 비용은 30분 간격이어도 일 ~270원 수준이라 부담이 없었다.

그런데 새벽 3시에 아무 일도 없는데 30분마다 호출하는 건 낭비다. 동적 주기로 바꿨다.

def _calc_interval(self):
    trades_1h = db.count_recent_trades(hours=1)
    news_1h = db.count_recent_news(hours=1)
    positions = len(portfolio.get_positions())

    if trades_1h >= 3 or news_1h >= 5:
        return 0.5   # 활발: 30분
    elif positions > 0:
        return 2      # 보유 중: 2시간
    else:
        return 4      # 한산: 4시간

일일 목표 ~30회, 비용 약 170원. 시장이 급변하면(1시간 내 5% 이상 변동) 대기 시간을 무시하고 즉시 분석하는 기능도 넣었다. 단, 일일 최대 60회 하드 리밋으로 과다 호출 방지.

전략 파라미터 런타임 반영 — CRITICAL 버그

이 모든 LLM 최적화가 의미 없어질 뻔한 버그가 있었다. 전략 인스턴스가 __init__에서 파라미터를 인스턴스 변수에 복사하는데, 이후 LLM이 파라미터를 바꿔도 인스턴스 변수는 갱신 안 됐다. LLM 조절이 통째로 무효화되고 있었던 것.

# 문제: __init__에서 한 번만 읽음
self.rsi_oversold = params.extra.get("rsi_oversold", 30)

# 수정: 매 틱마다 최신 파라미터 조회
@property
def rsi_oversold(self):
    return self.params.extra.get("rsi_oversold", 30)

이걸 놓치고 있었으면 "AI가 파라미터를 조절한다"는 기능 자체가 허상이었다.

웹 공개 — Vercel 배포 + 데모 모드

운영이 안정되니까 욕심이 났다. 이 대시보드를 외부에 공개하고 싶었다. Vercel에 프론트엔드를 배포하고, 비로그인 데모 모드를 추가해서 누구나 UI를 체험할 수 있게 했다.

공개 전 보안 강화도 필수였다. 로그인 rate limit(5회/분), JWT 시크릿 프로덕션 강제 검증, API URL 환경변수화, CORS 도메인 제한, 보안 헤더 추가. 데모 모드에서는 더미 데이터로 동작해서 실제 매매 데이터는 노출되지 않는다.

지금은

봇이 1분마다 시세를 보고, AI가 시장 상황에 맞춰 파라미터를 조절하고, 5중 검증으로 매매하고, 문제가 생기면 Slack으로 알려준다. 일일/주간/월간 리포트가 자동으로 생성되고, 웹으로 현황을 확인할 수 있다.

"사람이 안 봐도 되는 봇"에 완전히 도달했다고는 못 하지만, 꽤 가까워졌다. 가끔 Slack 알림이 오면 확인하는 정도. 그것마저도 대부분 봇이 알아서 처리한 결과를 알려주는 것이다.


반응형
댓글