멀티 타임프레임 자동매매 전략

멀티 타임프레임 분석이란?

멀티 타임프레임(MTF) 분석은 여러 시간 프레임의 차트를 동시에 분석하여 매매 신호의 신뢰도를 높이는 기법입니다. 단일 타임프레임만 보면 노이즈에 휘둘리기 쉽지만, 상위 타임프레임에서 추세를 확인하고 하위 타임프레임에서 진입 타이밍을 잡으면 승률과 손익비를 동시에 개선할 수 있습니다.

이 글에서는 파이썬으로 멀티 타임프레임 자동매매 시스템을 구현하는 방법을 실전 코드와 함께 설명합니다.

타임프레임 조합 원칙

효과적인 멀티 타임프레임 분석은 보통 3개 타임프레임을 조합합니다.

역할 스캘핑 데이트레이딩 스윙
상위 (추세) 15분 4시간 일봉
중위 (방향) 5분 1시간 4시간
하위 (진입) 1분 15분 1시간

핵심 원칙은 타임프레임 간 배수를 3~6배로 유지하는 것입니다. 1분과 일봉처럼 차이가 너무 크면 신호 간 괴리가 생겨 실용성이 떨어집니다.

파이썬 멀티 타임프레임 데이터 수집

ccxt로 여러 타임프레임의 OHLCV 데이터를 수집하는 클래스입니다.

import ccxt
import pandas as pd
from datetime import datetime

class MTFDataCollector:
    """멀티 타임프레임 OHLCV 데이터 수집기"""

    def __init__(self, exchange_id='binance', symbol='BTC/USDT'):
        self.exchange = getattr(ccxt, exchange_id)()
        self.symbol = symbol

    def fetch_ohlcv(self, timeframe, limit=200):
        """단일 타임프레임 OHLCV → DataFrame"""
        raw = self.exchange.fetch_ohlcv(
            self.symbol, timeframe, limit=limit
        )
        df = pd.DataFrame(raw, columns=[
            'timestamp', 'open', 'high', 'low', 'close', 'volume'
        ])
        df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
        df.set_index('timestamp', inplace=True)
        return df

    def fetch_multi(self, timeframes=['4h', '1h', '15m'], limit=200):
        """여러 타임프레임 동시 수집"""
        data = {}
        for tf in timeframes:
            data[tf] = self.fetch_ohlcv(tf, limit)
        return data

타임프레임별 지표 계산

각 타임프레임에서 독립적으로 기술 지표를 계산합니다. 상위 프레임에서는 추세, 하위 프레임에서는 모멘텀을 측정합니다.

import numpy as np

class MTFIndicators:
    """타임프레임별 기술 지표 계산"""

    @staticmethod
    def add_ema(df, period):
        """지수이동평균 추가"""
        df[f'ema_{period}'] = df['close'].ewm(span=period).mean()
        return df

    @staticmethod
    def add_rsi(df, period=14):
        """RSI 계산"""
        delta = df['close'].diff()
        gain = delta.where(delta > 0, 0).rolling(period).mean()
        loss = (-delta.where(delta < 0, 0)).rolling(period).mean()
        rs = gain / loss
        df['rsi'] = 100 - (100 / (1 + rs))
        return df

    @staticmethod
    def add_atr(df, period=14):
        """ATR (Average True Range) 계산"""
        high_low = df['high'] - df['low']
        high_close = abs(df['high'] - df['close'].shift())
        low_close = abs(df['low'] - df['close'].shift())
        tr = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1)
        df['atr'] = tr.rolling(period).mean()
        return df

    def compute_all(self, data_dict):
        """모든 타임프레임에 지표 추가"""
        for tf, df in data_dict.items():
            self.add_ema(df, 20)
            self.add_ema(df, 50)
            self.add_rsi(df)
            self.add_atr(df)
        return data_dict

멀티 타임프레임 신호 합성 전략

핵심은 상위→하위 순서로 필터링하는 것입니다. 상위 타임프레임이 상승 추세일 때만 하위에서 매수 신호를 취합니다.

class MTFStrategy:
    """멀티 타임프레임 추세 추종 전략"""

    def __init__(self, higher_tf='4h', mid_tf='1h', lower_tf='15m'):
        self.higher_tf = higher_tf
        self.mid_tf = mid_tf
        self.lower_tf = lower_tf

    def get_trend(self, df):
        """EMA 크로스 기반 추세 판단"""
        last = df.iloc[-1]
        if last['ema_20'] > last['ema_50']:
            return 'bullish'
        elif last['ema_20'] < last['ema_50']:
            return 'bearish'
        return 'neutral'

    def get_momentum(self, df):
        """RSI 기반 모멘텀 판단"""
        rsi = df.iloc[-1]['rsi']
        if rsi < 30:
            return 'oversold'
        elif rsi > 70:
            return 'overbought'
        return 'neutral'

    def generate_signal(self, data):
        """3개 타임프레임 신호 합성"""
        # 1단계: 상위 타임프레임 추세 확인
        higher_trend = self.get_trend(data[self.higher_tf])

        # 2단계: 중위 타임프레임 방향 확인
        mid_trend = self.get_trend(data[self.mid_tf])

        # 3단계: 하위 타임프레임 진입 신호
        lower_momentum = self.get_momentum(data[self.lower_tf])
        lower_trend = self.get_trend(data[self.lower_tf])

        signal = {
            'higher': higher_trend,
            'mid': mid_trend,
            'lower_trend': lower_trend,
            'lower_momentum': lower_momentum,
            'action': 'hold'
        }

        # 매수: 상위+중위 상승 + 하위 과매도 반등
        if (higher_trend == 'bullish' and
            mid_trend == 'bullish' and
            lower_momentum == 'oversold'):
            signal['action'] = 'buy'
            signal['confidence'] = 'high'

        # 매도: 상위+중위 하락 + 하위 과매수
        elif (higher_trend == 'bearish' and
              mid_trend == 'bearish' and
              lower_momentum == 'overbought'):
            signal['action'] = 'sell'
            signal['confidence'] = 'high'

        # 중간 확신: 상위만 일치
        elif higher_trend == 'bullish' and lower_momentum == 'oversold':
            signal['action'] = 'buy'
            signal['confidence'] = 'medium'

        elif higher_trend == 'bearish' and lower_momentum == 'overbought':
            signal['action'] = 'sell'
            signal['confidence'] = 'medium'

        return signal

ATR 기반 동적 손절·익절 설정

멀티 타임프레임 전략에서는 상위 타임프레임의 ATR을 기준으로 손절·익절을 설정하면 노이즈에 의한 조기 청산을 방지할 수 있습니다.

class MTFRiskManager:
    """멀티 타임프레임 기반 리스크 관리"""

    def __init__(self, atr_sl_mult=1.5, atr_tp_mult=3.0):
        self.atr_sl_mult = atr_sl_mult   # 손절 = ATR × 1.5
        self.atr_tp_mult = atr_tp_mult   # 익절 = ATR × 3.0

    def calculate_levels(self, entry_price, atr, side):
        """ATR 기반 손절·익절 계산"""
        sl_distance = atr * self.atr_sl_mult
        tp_distance = atr * self.atr_tp_mult

        if side == 'buy':
            stop_loss = entry_price - sl_distance
            take_profit = entry_price + tp_distance
        else:
            stop_loss = entry_price + sl_distance
            take_profit = entry_price - tp_distance

        return {
            'entry': entry_price,
            'stop_loss': round(stop_loss, 2),
            'take_profit': round(take_profit, 2),
            'risk_reward': self.atr_tp_mult / self.atr_sl_mult,
            'sl_pct': sl_distance / entry_price * 100,
            'tp_pct': tp_distance / entry_price * 100
        }

전체 통합: MTF 자동매매 봇

위 모듈들을 하나로 통합한 실행 코드입니다. 자동매매 봇 만들기의 기본 구조에 MTF 로직을 추가합니다.

import time

def run_mtf_bot():
    """멀티 타임프레임 자동매매 봇 메인 루프"""
    collector = MTFDataCollector(symbol='BTC/USDT')
    indicators = MTFIndicators()
    strategy = MTFStrategy(
        higher_tf='4h', mid_tf='1h', lower_tf='15m'
    )
    risk = MTFRiskManager(atr_sl_mult=1.5, atr_tp_mult=3.0)

    timeframes = ['4h', '1h', '15m']
    position = None

    while True:
        try:
            # 데이터 수집 + 지표 계산
            data = collector.fetch_multi(timeframes)
            data = indicators.compute_all(data)

            # 신호 생성
            signal = strategy.generate_signal(data)
            print(f"신호: {signal}")

            # 포지션 없을 때만 진입
            if position is None and signal['action'] != 'hold':
                current_price = data['15m'].iloc[-1]['close']
                higher_atr = data['4h'].iloc[-1]['atr']

                levels = risk.calculate_levels(
                    current_price, higher_atr, signal['action']
                )
                print(f"진입: {signal['action']} @ {current_price}")
                print(f"손절: {levels['stop_loss']}, "
                      f"익절: {levels['take_profit']}")
                print(f"R:R = 1:{levels['risk_reward']:.1f}")

                position = {
                    'side': signal['action'],
                    'entry': current_price,
                    **levels
                }

            # 15분마다 체크 (하위 타임프레임 기준)
            time.sleep(900)

        except Exception as e:
            print(f"에러: {e}")
            time.sleep(60)

if __name__ == '__main__':
    run_mtf_bot()

MTF 전략의 장단점

장점 단점
거짓 신호 필터링으로 승률 향상 진입 기회 감소 (엄격한 조건)
큰 추세 방향과 일치하는 매매 API 호출 증가 (여러 타임프레임)
ATR 기반 동적 리스크 관리 타임프레임 간 신호 충돌 가능
다양한 시장 상황에 적응 파라미터 최적화 복잡도 증가

마치며

멀티 타임프레임 분석은 단일 지표만으로 매매하는 것보다 훨씬 안정적인 결과를 제공합니다. 상위 타임프레임으로 큰 추세를 확인하고, 하위 타임프레임에서 정밀한 진입점을 찾는 구조는 기관 트레이더들이 실제로 사용하는 접근법입니다.

모멘텀 자동매매 전략이나 평균회귀 전략에 MTF 필터를 추가하면 기존 전략의 성과를 크게 개선할 수 있습니다.

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