Risk Guards · 실계좌 전환 검증 · 사고 대응 프로토콜
자동매매 시스템의 핵심 리스크는 "한 번의 실수가 모든 걸 날릴 수 있다"는 점입니다. 사람은 이상한 주문을 보면 '어? 이거 뭐지?' 하고 멈추지만, 자동화는 코드가 시키는 대로 끝까지 실행합니다.
W8에서 배운 4단계 Guards. 모든 자동 주문은 이 4개를 순차 통과해야 합니다.
| Confidence | 자본 대비 할당 | 비고 |
|---|---|---|
| 1 (매우 낮음) | 1% | 실행 스킵 권장 |
| 2 (낮음) | 1.5% | - |
| 3 (보통) | 2% | 기본값 |
| 4 (높음) | 3% | ⭐ 적극 매수 |
| 5 (매우 높음) | 4% | 최대 한도 |
qty × price ≤ equity × 0.04 공식 테스트int()로 반드시 정수화# Bracket Order로 매수와 동시에 등록 def calculate_stop_loss(entry: float, stop_pct: float = 0.05) -> float: """손절가 + 손절-지정가 (slippage 보호)""" stop_trigger = entry * (1 - stop_pct) # 트리거: -5% stop_limit = entry * (1 - stop_pct) * 0.995 # 지정가: -5.5% return {'stop': round(stop_trigger, 2), 'limit': round(stop_limit, 2)}
| 저변동 ETF (SPY 등) | -3% |
| 대형주 (AAPL, 삼성전자) | -5% ⭐ |
| 중소형주 | -7~10% |
| 암호화폐 | -8~15% |
| Stop | Profit | R:R | 적합성 |
|---|---|---|---|
| -3% | +3% | 1:1 | 스캘핑, 비추천 |
| -5% | +10% | 1:2 ⭐ | 강의 기본값, 대부분 경우 |
| -5% | +15% | 1:3 | 추세 추종 전략 |
| -3% | +15% | 1:5 | 브레이크아웃, 승률 낮음 |
def daily_loss_guard(account) -> dict: equity = float(account['equity']) last_equity = float(account['last_equity']) daily_pnl_pct = (equity - last_equity) / last_equity * 100 if daily_pnl_pct < -2.0: return { 'allowed': False, 'reason': f'Daily loss {daily_pnl_pct:.2f}% exceeds -2% limit', 'action': 'HALT_ALL_TRADING' } if daily_pnl_pct < -1.5: # 경고 영역 return { 'allowed': True, 'warning': 'Approaching daily limit', 'reduce_size_factor': 0.5 # 포지션 절반 축소 } return {'allowed': True}
| 일일 손실 | 대응 |
|---|---|
| 0 ~ -1% | 정상 거래 |
| -1% ~ -1.5% | 경고, 포지션 크기 50%로 축소 |
| -1.5% ~ -2% | 심각 경고, 신규 매수 금지 (기존 포지션만 관리) |
| -2% 초과 | 🚨 전면 중단, Discord 긴급 알림, 다음 영업일까지 거래 금지 |
자동화 수준을 점진적으로 높이는 안전장치. AI가 제안하고, 사람이 최종 승인하는 구조.
# 1. AI Agent 결과 → Discord에 "승인 대기" 메시지 발송 # 2. Webhook 노드로 Discord 버튼 응답 대기 # 3. 승인되면 주문 실행, 거부되면 로그만 # Discord embed payload 예시: { "embeds": [{ "title": "🤖 주문 승인 요청", "description": "AAPL BUY 10주 @ $180", "fields": [ {"name": "Confidence", "value": "4/5", "inline": true}, {"name": "Stop", "value": "$171 (-5%)", "inline": true}, {"name": "Target", "value": "$198 (+10%)", "inline": true} ], "footer": {"text": "5분 내 응답 없으면 자동 취소"} }], "components": [{ "type": 1, "components": [ {"type": 2, "style": 3, "label": "✅ 승인", "custom_id": "approve_AAPL_20260422"}, {"type": 2, "style": 4, "label": "❌ 거부", "custom_id": "reject_AAPL_20260422"} ] }] }
"기록되지 않은 것은 발생하지 않은 것"이라는 IT 업계 격언. 사고 발생 시 재현 가능성이 생명입니다.
| 로그 레벨 | 보관 기간 | 이유 |
|---|---|---|
| Decision Log | 최소 3개월 | 전략 개선·백테스트 재현 |
| Order Log | 최소 1년 | 세무·분쟁·감사 대비 |
| Error Log | 최소 6개월 | 시스템 개선 패턴 분석 |
Sharpe = (mean_return - risk_free) / std_deviation # 일별 수익률 기준 daily_returns = df['daily_return_pct'] / 100 sharpe = (daily_returns.mean() * 252) / (daily_returns.std() * 15.87) print(f'Annualized Sharpe: {sharpe:.2f}')판정: < 0.5 불합격 / 0.5~1.0 재검토 / > 1.0 양호 / > 2.0 우수
df['cummax'] = df['equity'].cummax() df['drawdown'] = (df['equity'] - df['cummax']) / df['cummax'] * 100 max_dd = df['drawdown'].min() print(f'Max Drawdown: {max_dd:.2f}%')
E = (승률 × 평균수익) - (패율 × 평균손실)# Kill Switch — 전 포지션 즉시 청산 def emergency_close_all(): """모든 포지션 시장가 청산 + 워크플로 중단.""" # 1. 대기 주문 전량 취소 requests.delete(f'{BASE_URL}/v2/orders', headers=HEADERS) # 2. 모든 포지션 청산 positions = get_positions() for p in positions: requests.delete(f'{BASE_URL}/v2/positions/{p.symbol}', headers=HEADERS) # 3. Discord 알림 notify('🚨 Emergency close executed')
사고는 준비된 사람만이 빠르게 복구합니다. 아래 순서를 사전에 반복 연습하세요.
| 증상 | 가능한 원인 | 1차 대응 |
|---|---|---|
| 예상 외 주문 체결 | 프롬프트 버그 / AI 오판 | 해당 워크플로 중단 → 포지션 유지 가능성 판단 |
| 연속 Guard 4 발동 | 시장 급변 / 전략 부적합 | 시스템 중단 → 1주일 이상 관망 → 전략 재검토 |
| 주문 중복 체결 | Rate Limit 대응 재시도 실수 | 즉시 중단 → 중복 분량 수동 청산 |
| API 인증 에러 폭주 | 토큰 만료 / 키 유출 | API 키 즉시 재발급 → 보안 점검 |
| 계정 접근 불가 | 해킹 가능성 | 증권사 고객센터 긴급 연락 → 모든 키 교체 |
모의투자 단계에서도 배포 전 이 리스트를 전부 체크하는 습관을 들이세요. 실전에서는 필수입니다.