자동매매 봇의 안전장치 설계
자동매매 봇에서 전략보다 먼저 잘 만들어야 하는 것은 안전장치입니다. 전략이 틀리면 조금 잃지만, 안전장치가 없으면 계좌를 통째로 잃습니다. 실제 봇을 운영하며 반드시 넣게 된 장치들을 정리합니다.
⚠️ 이 글은 교육·정보 제공 목적입니다. 투자 권유가 아니며, 투자 손실 책임은 본인에게 있습니다.
1. 강제청산 — 하루를 넘기지 않는다
일중 전략은 포지션을 다음 날로 넘기지 않는 것이 첫 번째 규칙입니다. 오버나이트 갭 리스크를 원천 차단하기 위해서입니다. 이를 위해 전략 엔진과 완전히 분리된 강제청산 고루틴을 둡니다.
전략 엔진(strategyEngine) : 갭 시그널로 진입/청산 판단
강제청산(forceLiquidation) : 15:20 단일 체크 → IsOpen 포지션 전부 시장가 청산
강제청산을 별도 고루틴으로 뺀 이유는, 전략이 어떤 상태에 있든 정해진 시각에는 무조건 실행되어야 하기 때문입니다. 장 마감 직전 호가가 얇아 실패할 수 있으니, 시장가 주문으로 1분 간격 3회까지 재시도하고 그래도 실패하면 즉시 긴급 알림을 보냅니다.
2. 중복 진입 방지 — 세 겹의 잠금
실시간 시그널은 초당 여러 번 들어옵니다. 방심하면 같은 포지션을 두 번, 세 번 잡습니다. 이를 세 겹으로 막습니다.
posMu.Lock() // 1) 뮤텍스로 동시 진입 차단
defer posMu.Unlock()
if pos.IsOpen { // 2) 이미 열린 포지션이면 즉시 skip
return
}
if time.Since(pos.LastOrderTime) < debounce { // 3) 디바운스(예: 30초)
return
}
// 진입 직후 곧바로 IsOpen=true 로 마킹 → 다음 시그널이 바로 들어와도 차단
핵심은 진입 주문을 보낸 직후 즉시 IsOpen=true로 마킹하는 것입니다. 체결 응답을 기다리는 사이 다음 시그널이 들어와도 중복 진입이 차단됩니다.
3. 진입 전 게이트 — 여러 개의 가드
주문을 내기 전, 통과해야 할 관문을 여러 개 둡니다.
- 시간 가드: 개장 직후 5분간은 시가·호가가 불안정하므로 진입 금지. 강제청산 직전(예: 15:10 이후)에도 신규 진입 금지.
- 극단 변동률 가드: 기초자산 변동률이 ±15%를 넘으면 이상거래로 보고 skip.
- 호가 깊이 가드: 매도호가 잔량 × 가격이 주문 금액의 절반에 못 미치면, 체결이 안 될 위험이 크므로 skip.
- 데이터 신선도 가드: 마지막 체결 수신이 10초를 넘었으면 시그널을 신뢰하지 않음.
이 가드들은 "좋은 기회를 놓치더라도 나쁜 진입은 막는다"는 원칙의 구현입니다.
4. 상태 영속화 — 재시작을 견딘다
봇은 배포·점검·크래시로 언제든 재시작됩니다. 메모리에만 있던 포지션·기준선이 날아가면 봇은 자기가 뭘 들고 있는지 모르는 상태가 됩니다. 그래서 핵심 상태를 JSON 파일로 영속화합니다.
bot_state.json : 봇 실행 상태(running 여부 등)
positions.json : 현재 포지션 (수량·평단·진입시각·IsOpen)
baseline.json : 당일 시가 기준선 (날짜 포함)
재시작 시 이 파일들을 읽어 복구합니다. 이때 날짜 검사가 중요합니다. baseline.json의 거래일이 오늘과 다르면 통째로 폐기하고 새로 캡처합니다. 어제 시가로 오늘 갭을 계산하는 참사를 막기 위해서입니다.
if saved.TradingDate != today {
baselines = map[string]*BaselineSnapshot{} // 날짜 바뀜 → 폐기
}
또, 장중에 재시작했는데 이미 열린 포지션이 있고 강제청산 시각을 넘겼다면, 복구 직후 바로 청산 큐에 넣습니다.
5. 자격증명 보호 — 평문 금지
API 키와 시크릿은 절대 평문으로 두지 않습니다. 실제 봇에서는 AES-GCM으로 암호화해 저장합니다.
gcm, _ := cipher.NewGCM(block)
nonce := make([]byte, gcm.NonceSize())
io.ReadFull(rand.Reader, nonce)
ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
여기에 더해, 종목코드 같은 입력값도 검증합니다. 6자리 숫자가 아니면 아예 주문 경로로 넘기지 않습니다 — 잘못된 심볼로 엉뚱한 주문이 나가는 것을 막는 마지막 방어선입니다.
정리
안전장치는 화려하지 않지만, 봇의 수명을 결정합니다. 강제청산으로 하루를 넘기지 않고, 세 겹 잠금으로 중복을 막고, 여러 가드로 나쁜 진입을 거르고, 상태를 파일로 남겨 재시작을 견디고, 자격증명을 암호화한다 — 이 다섯 가지가 갖춰지기 전에는 실전 자금을 넣지 않는 편이 좋습니다.
댓글
댓글 쓰기