자동매매 손절 전략 5가지 비교

손절이 자동매매의 생존을 결정한다

자동매매 봇을 운영하면서 가장 많이 간과하는 부분이 손절(Stop-Loss) 전략입니다. 진입 로직에는 수십 시간을 투자하면서, 손절은 고정 퍼센트 하나로 끝내는 경우가 대부분입니다. 하지만 실전에서 계좌를 지키는 것은 진입이 아니라 청산입니다.

이 글에서는 자동매매 봇에 적용할 수 있는 5가지 손절 전략을 비교하고, 각 전략의 장단점과 적합한 시장 상황을 정리합니다.

1. 고정 퍼센트 손절 (Fixed Percentage Stop)

가장 단순한 방식으로, 진입가 대비 일정 비율(예: -2%) 하락 시 청산합니다.

stop_price = entry_price * (1 - stop_pct)
# 예: 진입가 50,000 × (1 - 0.02) = 49,000에서 손절

장점: 구현이 간단하고 예측 가능한 최대 손실을 보장합니다. 계좌 생존 규칙에서 강조하는 1회 매매 최대 손실 한도를 정확히 지킬 수 있습니다.

단점: 변동성을 고려하지 않습니다. 변동성이 큰 장세에서는 정상적인 가격 흔들림에도 손절이 발동하고, 변동성이 낮을 때는 손절폭이 지나치게 넓어 불필요한 손실이 커집니다.

적합한 상황: 빠른 프로토타이핑, 전략 초기 테스트 단계

2. ATR 기반 손절 (Volatility-Based Stop)

ATR(Average True Range)을 활용하면 현재 시장 변동성에 맞춰 손절폭을 자동 조절할 수 있습니다.

import pandas as pd

def calculate_atr(high, low, close, period=14):
    tr = pd.concat([
        high - low,
        (high - close.shift(1)).abs(),
        (low - close.shift(1)).abs()
    ], axis=1).max(axis=1)
    return tr.rolling(period).mean()

atr = calculate_atr(df['high'], df['low'], df['close'])
stop_price = entry_price - (atr_multiplier * atr.iloc[-1])
# 일반적으로 atr_multiplier = 1.5 ~ 3.0

장점: 변동성이 커지면 손절폭이 넓어져 노이즈에 의한 조기 청산을 방지합니다. 변동성이 줄면 손절폭이 좁아져 손실을 최소화합니다.

단점: ATR 기간과 배수(multiplier) 설정에 따라 성과가 크게 달라집니다. 백테스트 시 과최적화에 빠지기 쉬운 부분입니다.

적합한 상황: 추세추종 전략, 변동성이 자주 바뀌는 코인 시장

3. 트레일링 스탑 (Trailing Stop)

트레일링 스탑은 가격이 유리한 방향으로 움직일 때 손절선도 함께 올려주는 동적 손절입니다. 수익을 보호하면서 추세를 최대한 따라갑니다.

class TrailingStop:
    def __init__(self, trail_pct=0.03):
        self.trail_pct = trail_pct
        self.highest = None
    
    def update(self, current_price):
        if self.highest is None or current_price > self.highest:
            self.highest = current_price
        stop_level = self.highest * (1 - self.trail_pct)
        return current_price <= stop_level  # True면 손절

고정 퍼센트 트레일링 외에도 ATR 기반 트레일링을 조합하면 더 정교해집니다:

  • 퍼센트 트레일링: 최고가 대비 N% 하락 시 청산
  • ATR 트레일링: 최고가 – (ATR × 배수) 아래로 하락 시 청산
  • 찬들리어 이탈(Chandelier Exit): 22일 최고가 – 3×ATR 방식의 고전적 트레일링

장점: 큰 추세에서 수익을 극대화합니다. 수익이 나기 시작하면 손절선이 올라가므로 최소한의 이익을 확보합니다.

단점: 횡보 장세에서 짧은 반등 후 다시 하락할 때, 중간에 트레일링이 올라가서 손절이 빨리 발동될 수 있습니다.

4. 시간 기반 손절 (Time Stop)

일정 시간 내에 기대한 방향으로 움직이지 않으면 청산하는 전략입니다. 가격 기반 손절과 병행하면 효과적입니다.

# 진입 후 N개 봉(캔들) 이내에 목표 수익에 도달하지 않으면 청산
max_holding_bars = 20

if bars_since_entry >= max_holding_bars:
    close_position()  # 시간 초과 → 청산

장점: 자본이 비효율적으로 묶이는 것을 방지합니다. 기회비용을 고려하면, 움직이지 않는 포지션을 오래 들고 있는 것보다 새로운 기회를 찾는 것이 낫습니다.

단점: 최적 보유 기간을 결정하기 어렵습니다. 너무 짧으면 유효한 포지션을 조기 청산하고, 너무 길면 의미가 없습니다.

적합한 상황: 평균회귀 전략, 페어 트레이딩에서 스프레드 회귀 기간 제한용

5. 기술적 레벨 손절 (Technical Stop)

지지/저항선, 이동평균, 볼린저밴드 등 기술적 분석 레벨을 손절 기준으로 사용합니다.

기술적 기준 손절 조건 적합한 전략
이동평균선 (MA) 20일 MA 하향 이탈 추세추종
볼린저밴드 하단밴드 이탈 후 미회복 평균회귀
직전 저점 스윙 로우(Swing Low) 하회 돌파/스윙
피봇 포인트 S1/S2 지지 레벨 이탈 단타/데이트레이딩

장점: 시장 구조에 기반하므로 논리적 타당성이 높습니다. “이 레벨이 깨지면 내 진입 근거가 무효화된다”는 명확한 기준을 제공합니다.

단점: 자동화가 상대적으로 복잡하며, 동적으로 변하는 레벨을 실시간 계산해야 합니다.

복합 손절: 실전 자동매매 봇 설계

실전에서는 단일 손절 방식보다 복합 손절이 효과적입니다. 여러 조건 중 가장 먼저 발동하는 것을 적용합니다:

def check_exit(position, current_price, current_bar, atr):
    # 1차: 절대 손실 한도 (최후의 방어선)
    if unrealized_pnl_pct(position, current_price) <= -0.05:
        return "MAX_LOSS_STOP"
    
    # 2차: ATR 트레일링 스탑
    trailing_level = position.highest_price - (2.5 * atr)
    if current_price = 30:
        return "TIME_STOP"
    
    return None  # 유지

이 구조의 핵심은 계층적 방어입니다. 트레일링이 수익을 보호하고, 시간 손절이 자본 효율을 관리하며, 최대 손실 한도가 최악의 시나리오를 차단합니다.

마무리

어떤 손절 전략이든 없는 것보다는 낫습니다. 하지만 자동매매에서 최적의 성과를 내려면, 전략의 특성과 시장 환경에 맞는 손절을 선택하고 조합해야 합니다. 고정 퍼센트로 시작해서, ATR 기반으로 진화하고, 트레일링과 시간 손절을 추가하는 단계적 접근을 권장합니다.

손절은 “손해를 보는 것”이 아니라, 더 큰 손해를 막는 투자입니다. 자동매매 봇의 코드 한 줄이 계좌 전체를 지킵니다.

7) 손절 전략별 파이썬 구현 코드

5가지 손절 전략을 모두 코드로 구현하여 백테스트에서 비교할 수 있게 합니다.

from abc import ABC, abstractmethod

class StopLossStrategy(ABC):
    @abstractmethod
    def should_stop(self, entry_price: float, current_price: float,
                    high_since_entry: float, atr: float) -> bool:
        pass

class FixedPercentStop(StopLossStrategy):
    """고정 퍼센트 손절"""
    def __init__(self, pct: float = 2.0):
        self.pct = pct / 100

    def should_stop(self, entry_price, current_price, high_since_entry, atr):
        return current_price <= entry_price * (1 - self.pct)

class TrailingStop(StopLossStrategy):
    """트레일링 스탑: 고점 대비 N% 하락 시 청산"""
    def __init__(self, trail_pct: float = 3.0):
        self.trail_pct = trail_pct / 100

    def should_stop(self, entry_price, current_price, high_since_entry, atr):
        return current_price <= high_since_entry * (1 - self.trail_pct)

class ATRStop(StopLossStrategy):
    """ATR 기반 손절: 진입가 - N * ATR"""
    def __init__(self, multiplier: float = 2.0):
        self.multiplier = multiplier

    def should_stop(self, entry_price, current_price, high_since_entry, atr):
        stop_price = entry_price - (self.multiplier * atr)
        return current_price = self.max_bars and current_price = entry_price * (1 + self.trigger_pct):
            self._breakeven_activated = True
        stop = entry_price if self._breakeven_activated else entry_price * (1 - self.initial_stop_pct)
        return current_price <= stop

8) 백테스트 비교 결과 해석법

손절 전략을 비교할 때 단순 수익률만 보면 안 됩니다. 위험 조정 수익률까지 봐야 실전에서 유효한 전략을 고를 수 있습니다.

  • 승률(Win Rate): 높다고 좋은 게 아님. 손익비와 함께 봐야 함.
  • 평균 손실 대비 평균 수익: 1:2 이상이면 승률 40%로도 수익 가능.
  • 최대 연속 손실 횟수: 심리적 한계와 직결. 5연패 이상이면 전략 재검토.
  • MDD: 15% 이상이면 실전에서 감정적으로 버티기 어려움.

9) 관련 글

위로 스크롤
WordPress Appliance - Powered by TurnKey Linux