본문으로 건너뛰기

페이퍼 → 라이브

quant-ai의 라이브 모드는 다단계 게이트로 보호됩니다. 본 페이지는 운영자가 사용자의 라이브 승급을 검토 / 승인 / 사후 모니터링하는 절차를 다룹니다. 사용자 시점의 절차는 튜토리얼 — 라이브 모드로 졸업 참조.

게이트 4종

flowchart LR
A[페이퍼 검증<br/>90d / 50 trades] --> B[HMAC confirm token<br/>12h 유효]
B --> C[reCAPTCHA v3<br/>봇 차단]
C --> D[ALLOW_LIVE=1<br/>VM 호스트 환경변수]
D --> E[FEATURE_EQUITY_LIVE=true<br/>compose env]
E --> F[LIVE_DAILY_TRADE_LIMIT<br/>일일 상한]
게이트위치책임우회 가능?
페이퍼 검증OperationsService.is_live_ready()사용자가 충분히 검증했는지운영자가 RISK_PAPER_MIN_* 임시 하향
HMAC confirmOperationsService.issue_confirm_token이메일 소유 검증불가 (DB에 sha256 hash만)
reCAPTCHAAPI 미들웨어봇 차단RECAPTCHA_SECRET_KEY 빈값이면 스킵 (개발용)
ALLOW_LIVEVM 호스트 envprod 이중 잠금호스트 root 접근 필요
LIVE_DAILY_TRADE_LIMITAPI 라우터폭주 방지환경변수 변경

사용자 승급 흐름 (운영자 시점)

1. 사전 요건 확인

변수운영자 점검
RISK_PAPER_MIN_DAYS기본 90. 임시 하향 시 사후 사용자별 모니터링 의무
RISK_PAPER_MIN_TRADES기본 50
RECAPTCHA_SECRET_KEY운영에서 반드시 설정. 빈값이면 검증 스킵
LIVE_CONFIRM_SECRET빈값이면 AUTH_SECRET_KEY 폴백. placeholder 금지 (changeme 등)
SMTP_*비어 있으면 confirm 토큰을 로그에만 남김 (개발용). 운영에서는 SMTP 필수

OperationsService._resolve_secret()이 placeholder 값을 거부하므로, 잘못 설정된 운영 환경은 부팅 시점에 즉시 실패합니다.

2. 사용자 승급 요청 처리

사용자가 UI에서 "라이브 승급" 버튼을 누르면:

1. POST /api/operations/live/readiness
→ server/services/operations.py::is_live_ready()
→ PaperStats(days_active, paper_trades_count) 계산
→ 두 임계 모두 통과 시 ok=True

2. POST /api/operations/live/confirm/issue
→ issue_confirm_token() — HMAC 토큰 12h 유효
→ DB에 sha256 hash만 저장, 평문은 SMTP로 1회 전송

3. 사용자가 이메일에서 토큰을 가져옴 / reCAPTCHA 통과

4. POST /api/operations/live/enable {confirm_token}
→ consume_confirm_token() — HMAC 검증 + DB row burn
→ set_live_enabled() — UserSettingsRow.live_enabled[asset_class]=true

운영자 개입 포인트:

  • 임계 미달인데 승급 요청 → 페이퍼 검증 페이지로 안내. 임시 하향이 필요한 경우 사후 추적 의무.
  • confirm 이메일 미수신 → SMTP 로그 확인. 토큰 평문은 DB에 없으므로 재발급 (issue_confirm_token이 기존 활성 토큰을 자동 비활성화).
  • 사용자가 봇이 의심됨 → reCAPTCHA 점수 확인 후 수동 차단.

3. 첫 라이브 주문

OperationsService.mark_first_live_order()이 첫 호출 시점을 기록합니다.

# 첫 라이브 주문 시 broker layer가 첫 호출에 한해 True를 받음 →
# broker_order_events에 first_live_order=true 마커
existing = settings.live_first_order_at.get(asset_class.value)
if not existing:
settings.live_first_order_at[asset_class.value] = now.isoformat()
return True
return False

운영자는 Grafana — Multi-Asset Overview 에서 broker_order_events 첫 라이브 마커가 뜨면 사용자별 모니터링을 시작합니다 — 첫 라이브 24h는 가장 위험한 윈도우입니다.

4. 일일 상한

# server/services/operations.py
def increment_live_daily_count(user_id, asset_class) -> int:
# UTC 자정에 자동 리셋
bucket = settings.live_daily_count[asset_class.value]
if bucket["date"] != today:
bucket = {"date": today, "count": 0}
bucket["count"] += 1
return bucket["count"]

기본 LIVE_DAILY_TRADE_LIMIT=10. 도달 시 API가 429를 반환하고 다음 UTC 자정까지 사용자별 라이브 주문 차단.

운영자가 일시 상향이 필요한 경우:

# .env
LIVE_DAILY_TRADE_LIMIT=20
docker compose restart api

상향 후 사용자에게 알림. 영구 변경은 디자인 리뷰 필요.

절차: 신규 사용자 라이브 승급 검토

# 1. 사용자 페이퍼 통계 (운영자 admin API 또는 직접 DB)
docker compose exec timescaledb psql -U quant -d quantai -c "
SELECT user_id, asset_class, mode, COUNT(*) AS n,
MIN(executed_at) AS oldest
FROM equity_trades
WHERE user_id = <USER_ID> AND mode='paper'
GROUP BY user_id, asset_class, mode;
"

# 2. UserSettings 현재 상태
docker compose exec timescaledb psql -U quant -d quantai -c "
SELECT user_id, live_enabled, live_first_order_at, live_daily_count
FROM user_settings WHERE user_id = <USER_ID>;
"

# 3. 미사용 confirm token 정리 (필요 시)
docker compose exec timescaledb psql -U quant -d quantai -c "
UPDATE live_confirm_tokens SET is_active = false
WHERE user_id = <USER_ID> AND consumed_at IS NULL;
"

검증

  • is_live_readyok=True
  • live_confirm_tokens.is_active = true인 1건이 있고 만료 12h 내
  • 사용자가 confirm 이메일 평문을 /enable에 제출 시 consume_confirm_token() 이 True
  • user_settings.live_enabled[asset_class] = true
  • 첫 라이브 주문 후 broker_order_events에 first_live_order 마커
  • Daily Loss Monitor 에서 해당 사용자가 표에 등장

회수 (라이브 비활성)

특정 사용자의 라이브를 즉시 비활성화하려면:

docker compose exec timescaledb psql -U quant -d quantai -c "
UPDATE user_settings
SET live_enabled = jsonb_set(live_enabled, '{us_equity}', 'false'::jsonb)
WHERE user_id = <USER_ID>;
"

이는 사용자 단위 emergency_stop과는 다릅니다 — emergency_stop은 24h 잠금이며 비상 정지에서 다룹니다.

트러블슈팅

증상원인 / 조치
is_live_ready 가 항상 falseequity_trades.mode='paper' 가 한 건도 없음. 페이퍼 모드 활성 여부 확인
Confirm 이메일이 평문 토큰을 안 보여줌SMTP 미설정 → API 로그에 confirm_token_plaintext=... 검색 (개발 환경 한정)
consume_confirm_token 이 False만 반환(a) 토큰 만료 12h 경과 (b) 다른 사용자가 발급 (c) 이미 consumed. live_confirm_tokens 직접 조회
라이브 활성화는 됐는데 주문이 503FEATURE_EQUITY_LIVE 또는 ALLOW_LIVE가 OFF (prod 이중 잠금). VM env 확인
LIVE_DAILY_TRADE_LIMIT 도달UTC 자정에 자동 리셋. 즉시 필요 시 상향 + api 재시작

관련 페이지