트레이딩 실행 레이어 설계: “결정”을 “주문”으로 바꾸는 마지막 1단계

최종 수정: 작성자: Finyul

백테스트는 잘 돌아가는데 실거래 연결이 무서운 이유는 단 하나입니다. “결정(Decision)”과 “주문(Order)” 사이에 현실이 끼어들기 때문입니다. 이 글은 Account State(계정/포지션 상태)를 입력으로 받아 제약·검증·주문 생성·실행 결과 반영까지 담당하는 트레이딩 실행 레이어(Execution Layer) 설계 청사진을 제공합니다.

전체 폐루프(분석→예측→결정→실행)가 먼저 필요하면 LLM 멀티에이전트 투자 시스템(MAS) 완전 가이드를 참고하세요.

트레이딩 실행 레이어가 필요한 이유 예시
결정 JSON은 OK인데 주문은 실패하는 현실 변수(상한/중복/거래정지/체결).

실행 레이어가 없는 자동매매는 왜 위험한가

결정은 “의도”이고, 주문은 “계약”이다

  • 결정: “+20% 늘리자” 같은 의도/정책
  • 주문: 거래소/브로커에 제출되는 정확한 계약(수량·가격·유효시간·조건)

실거래에선 아래가 항상 개입합니다: 포지션 상한, 증거금/현금 부족, 중복 주문, 거래정지, 부분체결, 슬리피지, 수수료, 지연. 즉 실행 레이어가 없으면 좋은 결정도 ‘나쁜 주문’으로 번역됩니다.

책임(Owner)입력출력실패 원인필요한 로그
Decision예측·제약 상태의도(포지션 조절)·action(예: increase_20)스키마/도메인 위반decision_id, rationale, constraints_applied
OrderAccount State·결정·시장 상태계약(수량·가격·유효시간)상한·스텝·중복·체결·슬리피지·세션·현금 부족·거래정지gate 결과, Order, Fill, 거부 사유

Account State란 무엇인가: 실행 레이어의 “유일한 진실(SSOT)”

Account State(계정 상태)는 “지금 계정이 어떤 상태인지”를 한 번에 담은 스냅샷입니다. 실행 레이어는 결정 JSON만 보지 않고 Account State를 반드시 함께 봅니다.

최소 Account State 스키마(추천)

  • 현금/가용현금, 통화
  • 보유 포지션(수량, 평균단가, 평가손익, 현재 비중)
  • 미체결 주문(open orders)
  • 리스크 제약(limit set): 최대 비중, 스텝, 일일/주간 거래 횟수, 손실 트리거
  • 시장/계정 플래그: 거래 가능 여부, 쿨다운(cooldown), 위험 상태(risk_flag)
  • 버전/추적: as_of, account_id, state_hash
트레이딩 실행 레이어에서 필요한 계정 상태 필드
Account State 최소 필드(현금/포지션/주문/제약/플래그).

샘플(Account State JSON)

{
  "account_id": "A-001",
  "as_of": "2026-03-04T10:00:00+09:00",
  "cash": {"available": 10000000, "currency": "KRW"},
  "positions": [
    {"symbol": "REIT_X", "qty": 100, "avg_price": 101.2, "market_price": 103.0, "weight": 0.20}
  ],
  "open_orders": [
    {"symbol": "REIT_X", "side": "BUY", "qty": 50, "status": "NEW"}
  ],
  "limits": {
    "max_weight": 0.60,
    "step_weight": 0.20,
    "max_trades_per_day": 3,
    "cooldown_minutes": 30
  },
  "flags": {"tradable": true, "cooldown": false, "risk_flag": []},
  "state_hash": "sha256:..."
}

참고

  • Account State는 계산값·추정이 아니라 브로커/거래소 실제 스냅샷이어야 한다.
  • 미체결 주문까지 포함해 동기화해야 한다.
  • 동기화가 어긋나면 실행 레이어가 잘못된 주문을 내보내 사고로 이어진다.

실행 레이어의 목표: “안전하게 번역하고, 안전하게 거부하고, 반드시 기록”하기

실행 레이어는 세 가지를 해야 합니다.

  • 결정→주문 번역(Translate): “increase_20”을 수량/주문 타입으로 바꾸기
  • 검증/제약(Validate & Constrain): 위반이면 주문 생성 금지 + HOLD(또는 축소)
  • 결과 반영(Update): 체결/부분체결/실패를 Account State와 로그에 반영

실행 레이어 파이프라인(권장): 5개의 게이트로 사고를 막아라

여기서 “게이트”는 통과하지 못하면 주문이 절대 나가지 않는 방화벽입니다.

  • Gate 1) 스키마 검증(JSON 파싱/필수 필드/허용 enum)
    결정 출력이 흔들리면 실행이 터집니다. 결정 JSON은 반드시 스키마로 고정하세요. LLM 에이전트 출력 표준화: JSON 스키마 템플릿으로 분석→예측→결정 연결하기를 참고하세요.
  • Gate 2) 리스크 제약 검증(포지션 상한/스텝/빈도/쿨다운)
    이미 max_weight에 근접하면 “increase_20”은 거부 또는 축소. 하루 거래 횟수 초과면 HOLD. 쿨다운 시간 내면 HOLD.
  • Gate 3) 계정 검증(현금·증거금·미체결·중복 주문)
    같은 방향의 미체결 주문이 있으면 중복 방지. 현금 부족이면 주문 수량 자동 축소(또는 거부).
  • Gate 4) 시장 검증(거래정지·호가 공백·세션)
    거래정지/서킷브레이커/세션 외 시간이면 주문 금지. 유동성 부족(호가 공백) 시 지정가/분할로 강제(또는 HOLD).
  • Gate 5) 주문 모델 검증(타입·유효시간·슬리피지/수수료 반영)
    시장가/지정가 선택 규칙. 예상 거래비용 반영(예: 연구 백테스트에서 사용한 0.03% = 0.0003 같은 형태로 가정값도 로그에 남김).
결정 출력이 검증을 통과해야만 주문이 나가는 트레이딩 실행 레이어 흐름: 결정→5게이트→주문/거부
실행 레이어 검증 게이트 흐름(결정→5게이트→주문/거부).

“결정→주문” 번역 규칙: 주문 모델(Order Model)을 먼저 고정하라

결정이 “increase_20”이면 주문은 무엇이 될까요? 이게 사람 머릿속에 있으면 시스템이 흔들립니다. Order Model을 문서로 고정하세요.

번역에 필요한 최소 입력

  • 결정 action(예: increase_20 / reduce_40 / hold)
  • Account State(현금, 현재 비중, open_orders)
  • 제약(limit set)
  • 시장 상태(세션, 유동성, 변동성 플래그)

번역 출력 예시

  • order_type: MKT / LMT / VWAP(분할) / IOC 등
  • qty 또는 target_weight
  • time_in_force: DAY/GTC
  • price (지정가일 때)
액션(action)의도권장 주문 타입수량(또는 목표비중) 산식예외 처리(거부·축소·분할)
close전량 청산MKT / LMT현재 보유 수량 전량부분체결 대비 로그. 상한·스텝·중복 시 축소/거부.
reduce_40비중 40%p 감소MKT / LMT현재 qty의 40% 또는 target 차이미체결 매도 있으면 중복 방지. 유동성 낮으면 분할(VWAP/지정가).
reduce_20비중 20%p 감소MKT / LMT현재 qty의 20% 또는 target 차이상한·스텝·중복 주문 시 축소/거부. 유동성 낮으면 분할.
hold유지주문 없음
increase_20비중 20%p 증가MKT / LMTtarget_weight·계정규모 → qty상한 초과 시 축소 또는 거부. 중복 주문 시 거부. 유동성 낮으면 분할(VWAP/지정가).
increase_40비중 40%p 증가MKT / LMTtarget_weight·계정규모 → qty상한·스텝·중복 주문 시 축소/거부. 유동성 낮으면 분할.
increase_upper_limit상한까지 증액MKT / LMTmax_weight와 현재 비중 차이 → qty이미 상한이면 주문 없음. 중복·유동성 시 축소/분할.

실행 레이어가 “실거래 공포”를 줄이는 전형적 Before/After

Before(실행 레이어 없음)

  • LLM 결정: “increase_40”
  • 실제 계정: 이미 비중 0.58, 상한 0.60, 미체결 BUY가 존재
  • → 결과: 중복 주문 + 상한 위반 시도 + 체결 꼬임
  • → 나중에 “왜 이렇게 됐지?”를 추적할 근거가 없음

After(실행 레이어 있음)

  • Gate 2에서 상한/스텝 검증 → increase_40 거부 또는 increase_20로 자동 축소
  • Gate 3에서 중복 주문 감지 → 새 주문 생성 금지(또는 기존 주문 수정)
  • 모든 과정이 로그에 남아 리플레이 가능
  • → “결정이 문제였나? 번역이 문제였나? 실행이 문제였나?”가 분리됩니다.
주문 실패 유형 Top5(운영 로그 기반).최근 4주 · run_id: REIT_X_001

실행 로그는 선택이 아니라 필수: 주문/체결/거부 사유가 남아야 개선된다

실행 레이어는 “좋은 주문을 내는 것”만큼 “왜 주문을 안 냈는지”가 중요합니다.

필수 로그(권장)

  • decision_id / run_id / inputs_hash
  • gate 통과/실패 결과 + failed_rule
  • 생성된 주문(Order)과 응답(status)
  • 체결(Fill) 정보(부분체결 포함)
  • 비용(수수료/슬리피지 추정)과 반영 방식

운영 전체 루틴(로그·리플레이·리뷰) 설계는 AI 트레이딩 운영의 핵심: 로그·리플레이·리뷰로 “왜 그 결정을 했는지” 남기는 법에서 이어집니다.

FAQ

자주 묻는 질문

백테스트는 되는데 실거래에서만 망가지는 이유는 뭔가요?
대부분 미체결/부분체결/슬리피지/세션/거래정지/중복 주문 같은 실행 변수가 백테스트에 없거나 단순화되어서입니다. 실행 레이어는 이 현실 변수를 "게이트"로 강제합니다.
실행 레이어는 LLM으로 만들면 안 되나요?
권장하지 않습니다. 실행은 검증 가능한 규칙 엔진이 맡아야 합니다(예외 처리/컴플라이언스/안전). LLM은 "결정/설명"까지가 적합합니다.
가장 먼저 넣어야 할 제약 1순위는?
포지션 상한 + 스텝 제한 + 중복 주문 방지 3개가 1순위입니다. 이것만 있어도 사고 확률이 크게 줄어듭니다.
HOLD(거부)도 로그에 남겨야 하나요?
반드시 남겨야 합니다. HOLD는 "아무것도 안 함"이 아니라 리스크를 선택한 결정이고, 다음 개선의 가장 좋은 단서입니다.

결론: 실행 레이어는 “마지막 단계”가 아니라 “생존 장치”다

  • Account State를 SSOT로 고정하고
  • 결정→주문 번역 규칙을 문서화하고
  • 5개 게이트로 안전하게 거부하고
  • 주문/체결/거부 사유를 로그로 남기면
  • 실거래 연결의 공포는 크게 줄어듭니다.
데이터 기준 시점
2026-02-25
계산 방식
LLM·멀티에이전트·실행 레이어 설계 개념 정리. 투자 권유 아님.
한계점
실제 구현·API·브로커 연동은 환경에 따라 다르며, 과장·보장 표현 없음.