본문 바로가기

투자 재테크

EMA 크로스 전략으로 매매 신호 만들기 — 바이비트 자동매매 실전 코드

자동매매 봇의 핵심은 "언제 사고 언제 팔 것인가"를 결정하는 전략입니다. 오늘은 가장 기본적이면서도 실전에서 많이 쓰이는 EMA(지수이동평균) 크로스 전략을 파이썬 코드로 구현해보겠습니다.

EMA란?

EMA(Exponential Moving Average)는 최근 가격에 더 높은 가중치를 주는 이동평균입니다. 단순이동평균(SMA)보다 최근 추세에 빠르게 반응하기 때문에 단기 트레이딩에 많이 사용됩니다.

우리가 사용할 EMA 조합은 다음과 같습니다.

EMA 21 — 단기 추세 (약 1주일)
EMA 55 — 중기 추세 (약 2~3주)
EMA 200 — 장기 추세 (큰 방향성 필터)

 

전략 로직

롱(매수) 진입 조건: EMA 21이 EMA 55를 위로 돌파하고(골든크로스), 현재 가격이 EMA 200 위에 있을 때

숏(매도) 진입 조건: EMA 21이 EMA 55를 아래로 돌파하고(데드크로스), 현재 가격이 EMA 200 아래에 있을 때

EMA 200은 큰 추세 필터 역할을 합니다. 상승장에서 숏을 치거나, 하락장에서 롱을 잡는 실수를 줄여줍니다.

 

파이썬 코드

import pandas as pd
from pybit.unified_trading import HTTP
from dotenv import load_dotenv
import os

load_dotenv()

session = HTTP(
    api_key=os.getenv("BYBIT_API_KEY"),
    api_secret=os.getenv("BYBIT_API_SECRET"),
    testnet=True
)

def get_candles(symbol="BTCUSDT", interval="60", limit=300):
    """캔들 데이터를 가져와서 DataFrame으로 변환"""
    result = session.get_kline(
        category="linear", symbol=symbol,
        interval=interval, limit=limit
    )
    data = result['result']['list']
    df = pd.DataFrame(data, columns=[
        'timestamp', 'open', 'high', 'low', 'close', 'volume', 'turnover'
    ])
    df['close'] = df['close'].astype(float)
    df = df.sort_values('timestamp').reset_index(drop=True)
    return df

def calculate_ema(df, periods=[21, 55, 200]):
    """EMA 지표 계산"""
    for p in periods:
        df[f'ema_{p}'] = df['close'].ewm(span=p, adjust=False).mean()
    return df

def check_signal(df):
    """매매 신호 확인"""
    latest = df.iloc[-1]
    prev = df.iloc[-2]
    
    price = latest['close']
    ema21 = latest['ema_21']
    ema55 = latest['ema_55']
    ema200 = latest['ema_200']
    
    prev_ema21 = prev['ema_21']
    prev_ema55 = prev['ema_55']
    
    # 골든크로스: EMA21이 EMA55를 상향 돌파
    golden_cross = prev_ema21 <= prev_ema55 and ema21 > ema55
    # 데드크로스: EMA21이 EMA55를 하향 돌파
    dead_cross = prev_ema21 >= prev_ema55 and ema21 < ema55
    
    if golden_cross and price > ema200:
        return "LONG"
    elif dead_cross and price < ema200:
        return "SHORT"
    else:
        return "HOLD"

# 실행
df = get_candles()
df = calculate_ema(df)
signal = check_signal(df)
print(f"현재 신호: {signal}")
print(f"현재가: {df.iloc[-1]['close']:.2f}")
print(f"EMA 21: {df.iloc[-1]['ema_21']:.2f}")
print(f"EMA 55: {df.iloc[-1]['ema_55']:.2f}")
print(f"EMA 200: {df.iloc[-1]['ema_200']:.2f}")

 

이 전략의 한계

EMA 크로스 전략은 추세장에서 강력하지만, 횡보장에서 연속 손절이 나올 수 있습니다. 이를 보완하기 위해 ATR(평균진폭) 기반 손절/익절 설정이 필요합니다. 이 부분은 다음 글에서 다루겠습니다.

 

※ 이 글은 투자 권유가 아닙니다. 암호화폐 투자는 원금 손실 위험이 있으며, 모든 투자 판단과 책임은 투자자 본인에게 있습니다.