English version available

Ratchet TP/SL — 이익은 올라가고 손실은 절대 안 내려간다

“왜 3% 수익이었는데 결국 손절이야?”

이건 Leo가 대시보드를 보면서 매일 하는 말이야.

봇이 포지션을 열고, 가격이 유리하게 3% 움직이고, Leo가 “오 수익이다!” 하는 순간 — 가격이 돌아와서 SL에 걸려. 수익이 손실로 변하는 마법.

Leo: “3%까지 갔으면 최소한 본전은 챙겨야지!”

나: “고정 TP/SL로는 불가능해. 가격이 TP까지 안 오면 수익이 0이고, SL에 걸리면 손실이야.”

Leo: “그러면 수익이 나면 SL을 올려!”

나: “그게 래칫이야.”

고정 TP/SL의 한계

OWL 초기에는 모든 전략이 고정 TP/SL을 썼어:

롱 진입: $70,000
TP: $71,400 (+2%)
SL: $69,300 (-1%)

문제 3가지:

1. 올 오어 낫싱 — TP에 도달하면 전액 수익, 안 도달하면 0. 가격이 +1.8%까지 갔다가 돌아오면? 0원.

2. 변동성 무시 — BTC가 하루에 5% 움직이는 날에도 TP 2%? 시장이 줄 수 있는 수익의 절반도 못 가져가.

3. SL은 진입가에 고정 — 아무리 수익이 나도 SL은 -1%에 꼼짝 않아. 5% 올랐다가 -1%까지 떨어지면 처음부터 다시.

트레일링 스탑을 먼저 만들었어. 근데 그것도 문제가 있었지.

트레일링 스탑의 한계

트레일링: 최고점에서 -1.5% 하락하면 청산

좋아 보이지? 근데:

  • 변동성이 큰 날: 잠깐 -1.5% 빠졌다가 바로 반등 → 불필요한 청산
  • 변동성이 작은 날: -1.5%가 영영 안 와서 포지션 계속 보유 → 결국 추세 반전에 전부 반납

고정 퍼센트 트레일링은 시장 변동성을 반영 못 해.

Leo: “시장이 얼마나 흔들리는지에 따라 달라져야 하는 거 아니야?”

나: “그래서 ATR을 쓰는 거야.”

ATR이 뭔데?

Average True Range — 최근 N개 캔들의 평균 변동폭.

BTC가 1시간에 평균 $500 움직이면 ATR = $500. 이걸 퍼센트로 환산하면 ATR% ≈ 0.7%.

ATR이 높으면 시장이 흔들리고 있고, 낮으면 조용해. 이걸 TP/SL에 반영하면:

  • ATR 높음 (변동성 큼): TP/SL 넓게 → 노이즈에 안 걸림
  • ATR 낮음 (변동성 작음): TP/SL 좁게 → 빠른 수익 확정

Ratchet: 한 방향으로만 돌아가는 톱니바퀴

래칫(Ratchet)은 기계 용어야. 한 방향으로만 회전하고 역회전은 불가능한 톱니바퀴. OWL의 Ratchet TP/SL도 같아:

TP는 올라가고, SL도 올라간다. 근데 SL은 절대 내려가지 않는다.

OWL 봇 모니터링 — 포지션 보유 중인 5개 봇, TP/SL 래칫 표시 포지션 필터 화면. 5개 봇이 포지션 보유 중. 각각 TP(초록)와 SL(빨강) 가격이 래칫으로 관리되고 있다. SOL Elliott Swing은 숏 $90.3 진입 → TP $85.79 / SL $90.12.

핵심 공식

class RatchetManager:
    def __init__(self, entry_price, side, initial_tp, initial_sl, atr_pct):
        self._step_size = entry_price * (atr_pct / 100 * 0.5)
        # Step = ATR% × 0.5
        # 예: BTC $70,000, ATR 2% → step = $700

Step = 가격이 이만큼 유리하게 움직이면 TP/SL을 한 칸 올려.

가격이 Step만큼 올라갈 때마다:
  SL 상향 = Step × 0.7  (보수적)
  TP 상향 = Step × 1.0  (공격적)

왜 SL은 0.7배만? TP는 “더 갈 수 있다”고 공격적으로, SL은 “되돌림 여유를 줘야 한다”고 보수적으로. 둘 다 1.0이면 변동성에 SL이 너무 빨리 올라와서 불필요한 청산이 생겨.

실제 예시: BTC 롱

진입: $70,000
ATR%: 2%
Step: $700 (= $70,000 × 2% × 0.5)
초기 TP: $72,100 (+3%)
초기 SL: $68,600 (-2%)

--- 가격이 $70,700으로 → Step 1 달성 ---
SL: $68,600 → $69,090 (+$490 = $700 × 0.7)
TP: $72,100 → $72,800 (+$700 = $700 × 1.0)

--- 가격이 $71,400으로 → Step 2 달성 ---
SL: $69,090 → $69,580 (+$490)
TP: $72,800 → $73,500 (+$700)
최소 보장: $70,140 (진입가+0.2%, 수수료 커버)

--- 가격이 $71,000으로 되돌림 ---
SL은 $69,580 그대로! 절대 하향 안 함!

Leo: “그러니까 가격이 올라갈 때마다 SL 바닥이 올라가는 거야?”

나: “맞아. 그리고 절대 내려가지 않아. 한 번 올라간 SL은 고정.”

Leo: “그러면 최악의 경우에도?”

나: “Step 2 이상이면 최소 진입가+0.2%는 보장돼. 수수료 빼고 미니 수익.”

SL 하향 금지 — 핵심 규칙

def _update_long(self, current_high):
    new_sl = self._sl + sl_up
    # SL 하향 금지 (항상 >= 이전값)
    self._sl = max(self._sl, new_sl)
    # 최소 진입가+0.2% 보장
    min_sl = self.entry_price * 1.002
    self._sl = max(self._sl, min_sl)

이 한 줄 max(self._sl, new_sl)이 전체 시스템의 핵심이야. 어떤 상황에서도 SL은 이전보다 높거나 같아야 해. 시장이 아무리 흔들려도 한 번 잡은 수익은 놓치지 않는다는 원칙.

TP 히트 ≠ 청산

기존 시스템에서 TP 히트 = 즉시 청산이었어. Ratchet에서는 달라:

TP 히트 → 청산 아님! → TP 더 올려
SL 히트 → 이때만 청산

TP는 목표가 아니라 래칫의 다음 단계를 트리거하는 이정표야. TP에 도달하면 “잘 가고 있으니까 TP를 더 높이고 SL도 올리자.” 이래서 큰 추세를 끝까지 탈 수 있어.

백테스트: 고정 대비 +64%p

방식총 PnLR:R평균 승리평균 패배
고정 TP/SL기준1.32$15.20$11.50
Ratchet+64%p2.16$24.80$11.48

승리 시 평균 수익이 $15→$24로 63% 증가. 패배 시 평균 손실은 거의 동일. 이기면 더 크게 이기고, 지면 같은 만큼 지는 구조.

R:R 1.32→2.16 — 1:2 이상이면 승률 40%로도 수익. Ratchet이 비대칭 수익 구조를 만들어주는 거야.

긴급 SL -4%

래칫과 별개로 절대 손실 한계 -4%를 설정해뒀어.

# 긴급 SL: 진입가 대비 -4%
emergency_sl = entry_price * 0.96  # 롱

래칫이 아직 Step 0이고 시장이 급락하면? 초기 SL(-2%)에서 잡히겠지만, 만약 슬리피지로 SL을 뚫으면 -4%에서 무조건 청산. 안전벨트의 안전벨트야.

상태 저장: 봇 재시작에도 살아남기

// .state/ratchet_sol_09.json
{
    "entry_price": 87.45,
    "side": "long",
    "tp": 90.949,
    "sl": 88.237,
    "atr_pct": 2.0,
    "peak": 89.2,
    "steps": 2,
    "step_size": 0.8745
}

래칫 상태를 JSON 파일로 저장해. 봇이 재시작돼도 TP/SL 위치를 잃지 않아. DB에도 실시간으로 TP/SL을 업데이트하니까 대시보드에서도 현재 래칫 상태를 볼 수 있어.

청산 태그: 뭐가 청산했는지 추적

✅TP       — TP 히트 (래칫에서는 거의 없음)
🔧Ratchet수익 — 래칫 SL 히트 (수익 확정)
🔧Ratchet   — 래칫 SL 히트 (손실 최소화)
🚨긴급SL    — -4% 긴급 청산
❌SL       — 초기 SL 히트

모든 청산에 태그를 달아. 나중에 “래칫이 얼마나 수익을 보호했는지” 분석할 수 있어.

실전에서 배운 것

워뇨띠 분할매도 실험:

Leo가 워뇨띠(유명 트레이더)의 분할매도를 적용하자고 했어. 수익 구간에서 50%, 75%, 100% 나눠 청산.

백테스트 결과: 오히려 손해. 왜? Ratchet은 R:R 3:1 구조인데, 분할매도는 큰 승리를 잘라먹어. 50%를 먼저 팔면 나머지 50%의 큰 수익만으로는 작은 손실을 상쇄하기 어려워.

Leo: “워뇨띠도 안 되나?”

나: “워뇨띠는 사람이니까 심리적으로 분할매도가 편해. 근데 봇은 심리가 없어. 수학적으로 최적인 걸 하면 돼.”

최적 조합: SOL 4h + 래칫 트레일링

  • PF 1.48, 180일 +$1,799
  • 이게 전체 전략 중 가장 높은 수익

오늘의 교훈

  1. 고정 TP/SL은 시장을 무시한다. ATR 기반으로 변동성에 맞춰야 노이즈에 안 걸리고 추세를 탄다.

  2. SL 하향 금지는 타협 불가. max(old_sl, new_sl) 한 줄이 전체 시스템을 지탱한다. 한 번 잡은 수익은 놓치지 마.

  3. TP 히트 ≠ 청산. TP는 이정표지 목적지가 아니야. TP를 계속 올려서 큰 추세를 끝까지 타라.

  4. 분할매도는 봇에게 불리하다. R:R 3:1 구조에서 큰 승리를 잘라먹으면 전체 수익이 줄어든다.

  5. 상태 저장은 필수. 봇 재시작, 서버 리붓에도 래칫 상태가 살아남아야 한다. JSON + DB 이중 저장.

  6. 긴급 SL은 래칫과 별개. 래칫이 아직 작동 전이라도 -4%에서 무조건 탈출. 안전벨트의 안전벨트.


시리즈 3 “Operations” 시작! 다음 글: 봇-전략 분리 아키텍처

댓글