[BE-08] 토스 OCO 조건부주문 어댑터
작업 내용 (설계 의도)
변경 사항
토스 /api/v1/conditional-orders를 호출하는 어댑터를 만든다. STOP(손절 트리거가) + PROFIT_RATE(목표 수익률)를 OCO 타입으로 쌍 등록해, 봇이 죽어도 브로커 측에서 손절이 작동하게 한다. 근거: ADR-004.
order 도메인에 신규 파일만 추가한다 — 기존 OrderGateway.kt·TossOrderGatewayImpl.kt는 수정하지 않는다(Single Writer 보호).
제약:
CONDITIONAL_ORDER레이트리밋 초당 5회 → 기존TossRateLimiterFacade에 그룹을 추가해 준수한다.- 계좌 스코프 API이므로
X-Tossinvest-Account헤더가 필수다(누락 시 400account-header-required). - 401 시 토큰 재발급 후 1회 재시도 — 기존
TossAuthClient#refresh패턴을 따른다.
롤백: 신규 파일 제거. 호출부(BE-10 LiveTradeExecutor)가 M4까지 동작하지 않으므로 되돌리기가 안전하다.
의존
- BE-01 (도메인 계약 —
ConditionalOrderGateway·OcoOrderSpec)
다이어그램
처리 흐름
sequenceDiagram participant Exec as LiveTradeExecutor participant Gw as TossConditionalOrderGatewayImpl participant Toss as Toss Open API Exec->>Gw: placeOcoOrder(spec) Gw->>Toss: POST /api/v1/conditional-orders Toss-->>Gw: conditionalOrderId Gw-->>Exec: conditionalOrderId
클래스 의존
flowchart LR Iface[ConditionalOrderGateway] -.->|implements| Impl[TossConditionalOrderGatewayImpl] Impl --> Client[tossRestClient] Impl --> Auth[TossAuthClient] Impl --> Limiter[TossRateLimiterFacade] Impl --> Dtos[TossConditionalOrderDtos]
테스트 케이스
- OCO 등록 성공 시
conditionalOrderId를 반환한다(MockWebServer). - 손절가와 목표수익률이 요청 본문의
first·second에 각각 담긴다. X-Tossinvest-Account헤더가 요청에 포함된다.- 401 응답 시 토큰을 재발급하고 1회 재시도한다.
- 429 응답 시 레이트리밋 예외를 던진다.
- 조건부 주문 취소가 정상 호출된다.