You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.7 KiB
5.7 KiB
Broker Integration & Order Lifecycle
1. 목적
이 문서는 브로커 연동 레이어와 주문 생명주기 규칙을 정의합니다. Phase 6에서는 최소 1개 브로커 reference 구현이 필요하며, 기본 reference는 Alpaca paper 입니다. 그러나 상위 코드가 특정 브로커 SDK에 직접 결합되면 안 되므로, 내부적으로는 broker abstraction layer를 사용합니다.
2. Broker Adapter 인터페이스
모든 adapter는 아래 메서드를 제공해야 합니다.
class BrokerAdapter(Protocol):
def get_health(self) -> BrokerHealth: ...
def get_account(self) -> BrokerAccountSnapshot: ...
def get_positions(self) -> list[BrokerPositionSnapshot]: ...
def get_open_orders(self) -> list[BrokerOrderSnapshot]: ...
def submit_order(self, order: PlannedOrder) -> SubmitResult: ...
def cancel_order(self, broker_order_id: str) -> CancelResult: ...
def replace_order(self, broker_order_id: str, patch: ReplacePatch) -> ReplaceResult: ...
def fetch_order(self, broker_order_id: str) -> BrokerOrderSnapshot: ...
def fetch_fills(self, since: datetime) -> list[BrokerFill]: ...
def stream_events(self, on_event: Callable[[RawBrokerEvent], None]) -> None: ...
금지사항
- adapter 바깥에서 브로커 SDK raw object를 직접 참조하지 않는다.
- business logic이 브로커별 order status string에 의존하지 않는다.
- adapter 내부에서 전략 점수나 리스크 결정을 하지 않는다.
3. Canonical Order Types
Phase 6 v1에서 허용하는 주문 타입은 아래로 제한한다.
marketlimitstopstop_limitmarket_on_open(브로커 지원 시)market_on_close(브로커 지원 시)
v1에서는 다음을 금지한다.
- 복합 브래킷 주문에 전략 로직을 위임하는 방식
- 옵션/멀티레그 주문
- 알고리즘 주문(TWAP/VWAP 등)
- after-hours 진입 전략 주문
4. Client Order ID 규칙
내부 시스템은 반드시 deterministic client_order_id를 생성해야 한다. 형식 예시:
{env}-{strategy_id}-{trade_date}-{symbol}-{leg}-{attempt}
예시:
paper-corelong-2026-03-12-NVDA-entry-01
paper-corelong-2026-03-12-NVDA-exit-half-01
규칙:
- 같은 logical order를 재전송할 때는 같은 id를 재사용할지, 새 시퀀스를 부여할지 명확히 해야 한다.
- submit timeout 후 실제로 브로커가 주문을 받았는지 불명확할 경우, 무조건 새 주문을 보내지 말고 먼저
fetch by client id또는 reconciliation을 수행한다.
5. PlannedOrder 구조
PlannedOrder는 최소 아래 필드를 가져야 한다.
order_plan_idcandidate_idsymbolsideqtynotional(optional)order_typetime_in_forcelimit_price(optional)stop_price(optional)submission_window_startsubmission_window_endexpiry_policybroker_route_hint(optional)reason_coderisk_snapshot_id
6. Order Lifecycle
6.1 내부 상태
planned
-> approved
-> submitted
-> accepted
-> partially_filled
-> filled
-> cancel_requested
-> cancelled
-> replace_requested
-> replaced
-> rejected
-> expired
-> busted
6.2 전이 규칙
planned -> approved: approval mode에서 승인 완료 또는 auto mode에서 risk guard 통과approved -> submitted: broker adapter submit 성공submitted -> accepted: broker가 ack 반환accepted -> partially_filled: 부분체결 event 수신partially_filled -> filled: 남은 수량이 0accepted -> cancel_requested: TTL 만료 / 운영자 cancel / risk haltaccepted -> rejected: broker rejectaccepted -> expired: broker day order expiredpartially_filled -> cancel_requested: 잔량 취소 요청replace_requested -> replaced: 새 broker order 또는 수정 반영 확인
7. Entry / Exit 주문 정책
7.1 Entry
v1 entry는 아래 정책만 허용한다.
- 다음 시초가 근처 market/limit 진입
- 장중 제한된 window 안의 limit 진입
- stop-limit 진입은 paper에서 충분히 검증된 전략에만 허용
7.2 Stop Exit
- 하드 stop을 브로커에 즉시 상주시키는지, 내부 synthetic stop으로 운용하는지 전략별로 고정한다.
- v1에서는 gap risk를 고려해 synthetic stop + session-based exit를 기본으로 한다.
- 단, 연결 장애가 잦은 환경에서는 broker-native stop을 허용할 수 있다.
7.3 Time Exit
- planned_time_exit 시각 또는 session close 기준으로 자동 청산 계획을 생성한다.
- time exit는 별도의 logical order leg로 기록한다.
8. Partial Fill 처리
partial fill은 예외가 아니라 정상 흐름이다.
정책:
- 평균 체결가를 지속 업데이트한다.
- 남은 수량이 min_fill_threshold 미만이면 즉시 취소/시장가 전환 여부를 전략별로 결정한다.
- exit 주문은 filled qty를 기준으로만 생성한다.
- stop/target leg는 filled qty와 정합해야 한다.
9. Cancel / Replace 정책
v1 원칙:
- replace는 실제로 필요한 경우에만 사용한다.
- submit 직후 수 초 내 교체를 반복하는 logic은 금지한다.
- 취소와 교체가 동시에 걸릴 수 있으므로, reconciliation 전 finality를 가정하지 않는다.
10. 브로커 event canonicalization
브로커 raw event는 아래 canonical event로 변환한다.
order_submittedorder_acceptedorder_rejectedorder_partially_filledorder_filledorder_cancel_requestedorder_cancelledorder_replacedorder_expiredtrade_bustheartbeat_lostheartbeat_restored
모든 event는 event_id, event_time, source, broker_order_id, client_order_id, payload_hash를 포함해야 한다.