11 / 12 · AUTO TRADING WIKI
주문 전 체크리스트와 안전장치
주문 요청을 차단하는 사전 점검과 상한·감사 기록의 역할을 설명합니다.
페이퍼 원장이 정확해도 실제 시장에서 같은 가격으로 체결되거나 같은 방식으로 복구된다는 보장은 없다. 이번 장의 목표는 실전 주문을 켜는 것이 아니라, 필요한 검토가 빠지면 진행을 차단하는 구조와 확인 기록을 만드는 것이다.
이 책의 교육용 구현은 기본값이 live_enabled = false이며 외부 실전 주문 전송 코드를 제공하지 않는다. 모든 점검이 통과해도 로컬 안전 점검까지만 끝난다. 예제에는 실계좌 번호·주문 비밀번호·실전 주문 요청이 없다.
1. 실행 환경의 의미를 다시 확인하기
simulation, paper, 증권사 모의투자, 실전은 서로 다른 환경이다. 모드 문자열 하나를 바꾸어 같은 연결을 쓰는 구조를 피하고, 데이터 조회와 주문 권한도 분리한다.
| 환경 | 이번 책에서 하는 일 | 돈과 주문 |
|---|---|---|
| 과거 시뮬레이션 | 확정 과거 가격으로 규칙 계산 | 외부 주문 없음 |
| 로컬 paper | 가상 의도·체결·현금 원장 | 외부 주문 없음 |
| 증권사 모의투자 | 별도 API 환경과 조건 검토 필요 | 이번 실습에서 연결하지 않음 |
| 실전 | 별도 운영 설계·승인·검증 필요 | 이번 실습에서 전송 불가 |
한국투자증권의 현재 API 문서와 공지는 KIS Developers 공식 개발자센터에서 확인한다. 모의투자 지원 범위, 인증·요청 규격, 호출 제한을 기억에 의존해 실전 코드에 복사하지 않는다. 이 책의 로컬 판정은 증권사의 서비스 승인이나 투자 적합성 검증을 대신하지 않는다.
2. 실전 검토 전 필요한 증거를 정하기
체크리스트는 “예” 표시를 모으는 문서가 아니다. 코드·설정·실행 기록과 연결된 증거 목록이다. 확인하지 않은 항목은 NOT_EVALUATED, 하나라도 실패한 항목은 FAIL로 두며 기본 상태를 통과로 만들지 않는다.
| 점검 영역 | 필요한 증거 | 차단 조건 |
|---|---|---|
| 데이터 | 원본·캘린더·조정 정책·확정 시각 | 원인 불명 누락·미확정 가격 |
| 규칙 | 전략 버전·설정 해시·T+1 연결 | 설명과 코드 불일치 |
| 원장 | 현금·수량·주문·체결 대조 | 차이 또는 출처 불명 기록 |
| 반복 실행 | 중복·중단·재개 시험 | 중복 정산 또는 복구 미검사 |
| 접근 권한 | 비밀값 보호·최소 권한 검토 | 로그·문서에 민감정보 노출 |
| 운영 | 중단 절차·담당자·복구 자료 | 문제 발생 시 중단 방법 없음 |
| 외부 주문 | 별도 설계와 검증 계획 | 이 교육용 구현에서는 미제공 |
“문제 없이 며칠 돌았다”라는 문장만으로 통과시키지 않는다. 몇 세션을 어떤 데이터로 처리했는지, 신호가 없던 날에도 중단 조건을 실제로 시험했는지 함께 쓴다. 정해진 횟수의 성공이 미래 안전을 증명하지는 않는다.
3. 설정은 기본 차단으로 읽기
config/safety.json 예시는 다음과 같다. 값이 없거나 타입이 다르거나 모르는 모드가 들어오면 오류로 종료한다. 환경변수의 문자열 "false"를 Python의 참값으로 잘못 처리하지 않도록 JSON의 불리언을 엄격하게 검사한다.
{
"mode": "paper",
"live_enabled": false,
"order_transport": "none",
"require_current_evidence": true,
"block_on_unknown_state": true,
"max_order_notional": "100000.00",
"max_open_positions": 3,
"kill_switch_path": "config/STOP_ALL"
}한도는 의도 생성 전에 검사하고, 체결 또는 전송 직전에도 현재 상태로 다시 검사하는 항목이다. 다만 이 장의 한도는 로컬 가상 자금 시험에만 쓰인다. 한도를 작게 적었다고 실전 주문 전송을 안전하게 구현한 것이 아니다.
mode = live를 오타로 쓴 상황, live_enabled를 문자열로 준 상황, 설정 파일을 읽지 못한 상황 모두 차단되어야 한다. 읽기 실패 시 “편의를 위해 기본 실전 설정 사용” 같은 대체 경로를 만들지 않는다.
4. 해제 기능 없는 교육용 차단 코드 만들기
아래 코드는 모드 검증의 방향을 보여주는 최소 예제다. 실전 전송 함수나 주문 URL이 없으며, live 요청은 어떤 설정에서도 종료된다. 실제 서비스에 필요한 위험 통제 전체를 구현한 코드는 아니다.
class SafetyBlocked(RuntimeError):
pass
def validate_educational_mode(config):
mode = config.get("mode")
enabled = config.get("live_enabled")
transport = config.get("order_transport")
if type(enabled) is not bool:
raise SafetyBlocked("live_enabled must be a JSON boolean")
if mode not in {"simulation", "paper", "live"}:
raise SafetyBlocked("unknown execution mode")
if mode == "live":
raise SafetyBlocked("live transport is not provided in this book")
if enabled or transport != "none":
raise SafetyBlocked("external order configuration is forbidden")
return mode
def educational_order_entry(config, paper_engine, intent):
mode = validate_educational_mode(config)
if mode != "paper":
raise SafetyBlocked("paper order entry requires paper mode")
return paper_engine.record_local_intent(intent)paper_engine에도 실제 HTTP 주문 호출을 넣지 않는다. 의존성을 로컬 원장 객체로 제한하고, 주문 연결 라이브러리를 가져오지 않는지 검사한다. 이름만 paper_engine인 실제 주문 클라이언트를 전달하면 설계 의도가 무너지므로 생성 위치와 의존성도 함께 검토한다.
검토 증거를 확인하는 절차는 이 함수 앞에 추가할 수 있다. 그러나 증거가 모두 PASS여도 이 예제의 live 차단은 그대로 유지한다. 이 장을 마친 뒤의 정상 상태는 실전 전송 기능 없음이다.
5. 통과 기록은 버전과 유효 범위를 묶기
safety_checks에는 개별 점검을, safety_reviews에는 전체 판단을 남긴다. 기록에는 review_id, 코드 버전, 설정 해시, 데이터 식별자, 생성 시각, 검토 범위, 증거 경로를 포함한다. 원래 기록을 덮어쓰지 않고 재검토를 새 기록으로 추가한다.
review_id=demo-safety-01 scope=educational_local_paper
code_version=demo-v1 strategy_version=cci20_cross_up_m100_v1
check=ledger_reconciliation result=PASS evidence=reconcile-demo.json
check=restart_after_commit result=PASS evidence=recovery-demo.json
check=live_transport_available result=NOT_PROVIDED
decision=LOCAL_PAPER_ONLY external_orders_permitted=false
설정이나 코드가 바뀌면 이전 검토의 해시와 달라진다. 그 경우 새 실행을 허용할지 다시 검토한다. 체크리스트를 한 번 작성하고 영구 허가증으로 사용하지 않는다. 오래된 증거의 허용 기간도 운영 문서에서 정하되 유효 기간만 지나지 않았다는 이유로 현재 상태 점검을 생략하지 않는다.
별도 실전 시스템을 설계한다면 실제 주문 접수·체결·잔고 조회·정정·취소·응답 유실의 정합성을 각각 검토해야 한다. 이번 원고에는 그 연결이 없으므로 관련 항목을 완료했다고 표시하지 않는다.
6. 응답이 없을 때 재주문하지 않는 이유 이해하기
로컬 원장에서는 같은 DB 트랜잭션으로 상태를 묶을 수 있었다. 외부 주문 시스템은 네트워크 너머에 있으므로 요청 결과를 받지 못했어도 주문이 접수되었을 가능성이 있다. 단순 재시도는 중복 주문을 만들 수 있다.
실전 연결을 별도로 개발할 때 필요한 상태는 SUBMISSION_UNKNOWN, 대조 절차, 재주문 금지 규칙이다. 실제 주문 내역과 체결 내역을 조회해 결과를 확인하기 전에는 “실패했으니 다시 보내기”를 하지 않아야 한다. 이번 교육용 코드에서는 외부 전송 자체를 막아 이 상황을 만들지 않는다.
가상 시험으로는 외부 서버를 호출하지 않고 “결과 불명” 사건을 주입할 수 있다. 기대 결과는 새 의도 생성 차단, 기존 상태 보존, 담당자 확인 요청 기록이다. 가상 시험이 실제 증권사 API의 동작을 검증한 것은 아니라고 보고서에 쓴다.
7. 중단 수단과 복구 수단을 함께 준비하기
중단 파일 config/STOP_ALL은 새 원장 변경 전에 확인한다. 모니터링 화면에 중단 버튼이 있더라도 프로그램이 실제로 신호를 읽고 종료하는지 시험한다. 화면에 “중단”이라고 보이는 것과 진행 중 작업이 정지한 것은 다를 수 있다.
중단 시 로그에는 마지막 확정 단계, 미완료 의도 수, 예약현금, 마지막 대조 시각을 남긴다. 예제의 중단은 가상 포지션 청산을 의미하지 않는다. 유지된 포지션과 미처리 이벤트가 무엇인지 보고하고 이후 대조 절차를 거친다.
복구할 수 있는 백업과 재현 자료가 있어야 중단 뒤 상태를 확인할 수 있다. 비밀값을 제거한 코드·설정 예제·스키마·실행 증거를 보관하고, DB 복구는 별도 테스트 환경에서 시험한다. 백업 파일의 존재와 복구 성공을 구분한다.
8. Codex에는 차단 점검을 요청하기
교육용 자동매매 프로젝트의 안전 기본값과 차단 경로를 점검해줘.
실전 주문 전송 코드는 추가하거나 실행하지 마.
mode 누락, 오타, 문자열 false, live 모드, 외부 transport 설정을 모두 차단해.
paper 경로가 로컬 원장만 사용하며 실제 주문 클라이언트를 읽지 않는지 확인해.
중단 파일·오래된 증거·설정 해시 변경·대조 불일치를 가상 데이터로 시험해.
확인한 증거와 미검사 항목을 구분하고 결론은 LOCAL_PAPER_ONLY로 남겨.
계좌번호·토큰·비밀값을 읽거나 로그에 표시하지 마.
학습용 시험에서 정상인 결과는 mode=live → SafetyBlocked다. 모든 체크리스트가 채워졌다는 이유로 전송 기능을 자동 생성하거나 실전 설정을 채우지 않는다. 별도 개발이 필요한 항목은 문서에 남긴다.
9. 완료 기준과 문제 해결
완료 기준은 기본 설정이 로컬 paper이고, 누락·오타·실전 요청이 차단되며, 점검 기록이 코드·설정 버전과 연결되는 것이다. 이번 장의 산출물은 체크리스트와 차단 시험 결과이며 실제 주문 성공 기록이 아니다.
| 증상 | 먼저 확인할 것 |
|---|---|
"false"인데 활성화됨 |
문자열의 참값 변환과 엄격한 타입 검사 |
| 모드 오타가 paper로 대체됨 | 허용 목록과 실패 시 종료 처리 |
| 이전 통과가 변경 코드에도 적용됨 | 코드 버전·설정 해시 대조 |
| 중단 버튼 후에도 처리가 진행됨 | 변경 직전 중단 확인과 진행 단계 표시 |
| 종합 결과가 “실전 준비 완료”임 | 범위에 맞는 LOCAL_PAPER_ONLY 판정 |
다음 장에서는 이 제한을 유지하면서 운영 기록과 변경 검토를 반복하는 방법을 정리한다.
공유 링크를 복사해 이어서 읽을 수 있습니다.