본문 바로가기
패션프로젝트/토이프로젝트

BTC 자동매매 시스템 구축기 1편 (PyUpbit + OpenAI GPT + Streamlit + MySQL)

by nowjin 2025. 3. 17.

🪙 GPT + PyUpbit 비트코인 자동매매 시스템 구축기

비트코인 자동매매 시스템을 직접 구축한 과정을 정리해보았습니다.
기술지표, 뉴스, 공포탐욕지수, GPT 판단까지 포함한 AI 기반 매매 시스템입니다.
파이썬을 검색해서 사용할 줄 안다는 가정하에 작성하였습니다.

■ 구성

  • 1편: MySQL 연결 + 기술적 지표 시스템
  • 2편: GPT로 회고 + AI 매매 판단 시스템
  • 3편: 실전 자동매매 + Streamlit 대시보드

📦 이번 편에서 다룰 내용

  • .env 설정: API Key, DB 접속 정보 보안 관리
  • db_manager.py: 거래로그 저장/조회 기능 구현
  • indicators.py: RSI, MACD, 볼린저밴드 등 기술적 지표 계산
  • pyupbit: 차트 데이터 수집 및 분석 적용

패키지 설치 및 Python 버전

Python 3.10.0 버전을 사용하였고, 패키지는 버전 고정 없이 설치했습니다.

pip install mysql-connector-python

Step 1. .env 환경 변수 설정

프로젝트 루트 디렉터리에 .env 파일을 생성합니다.
업비트 API KEY는 직접 발급 받아야 합니다.

UPBIT_ACCESS_KEY=your_upbit_key
UPBIT_SECRET_KEY=your_upbit_secret
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=btc_user
MYSQL_PASSWORD=secure_password
MYSQL_DB=btc_automation

Step 2. db_manager.py - 거래 로그 관리

기능 요약:

  • MySQL DB 연결
  • 거래내역 테이블 생성
  • 거래 로그 저장
  • 최근 거래 조회 (pandas DataFrame 반환)

구현 함수

  • connect_mysql() : MySQL 연결 객체 반환
  • init_db() : bitcoin_trades 테이블 생성
  • log_trade() : 거래 로그 1건 저장
  • get_recent_trades() : 최근 거래내역 조회

테이블 구조 (bitcoin_trades)

  • id : INT, 자동 증가 PK
  • timestamp : DATETIME, 거래 시간
  • decision : VARCHAR(10), 매수/매도/보유
  • percentage : INT, 비율
  • reason : TEXT, 판단 근거
  • btc_balance : DOUBLE, 보유 BTC
  • krw_balance : DOUBLE, 보유 원화
  • btc_avg_buy_price : DOUBLE, BTC 평단가
  • btc_krw_price : DOUBLE, 현재 BTC 가격
  • reflection : TEXT, AI 회고 내용
  • is_success : BOOLEAN, 성공 여부
  • failure_reason : TEXT, 실패 사유
  • headline : TEXT, 뉴스 제목 모음
  • week_performance : DOUBLE, 주간 수익률

코드

import mysql.connector
from mysql.connector import Error
import pandas as pd
from datetime import datetime, timedelta
import logging

logger = logging.getLogger(__name__)

def connect_mysql(mysql_host, mysql_port, mysql_user, mysql_password, mysql_db):
    try:
        conn = mysql.connector.connect(
            host=mysql_host,
            port=int(mysql_port),
            user=mysql_user,
            password=mysql_password,
            database=mysql_db
        )
        if conn.is_connected():
            logger.info("MySQL 연결 성공")
            return conn
    except Error as e:
        logger.error(f"MySQL 연결 실패: {e}")
        raise

def init_db(mysql_host, mysql_port, mysql_user, mysql_password, mysql_db):
    conn = connect_mysql(mysql_host, mysql_port, mysql_user, mysql_password, mysql_db)
    cursor = conn.cursor()
    try:
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS bitcoin_trades (
                id INT AUTO_INCREMENT PRIMARY KEY,
                timestamp DATETIME,
                decision VARCHAR(10),
                percentage INT,
                reason TEXT,
                btc_balance DOUBLE,
                krw_balance DOUBLE,
                btc_avg_buy_price DOUBLE,
                btc_krw_price DOUBLE,
                reflection TEXT,
                is_success BOOLEAN,
                failure_reason TEXT,
                headline TEXT,
                week_performance DOUBLE
            )
        """)
        conn.commit()
        logger.info("bitcoin_trades 테이블 생성 완료")
        return conn
    except Error as e:
        logger.error(f"DB 초기화 오류: {e}")
        conn.rollback()
        raise

def log_trade(conn, decision, percentage, reason, btc_balance, krw_balance,
              btc_avg_buy_price, btc_krw_price, reflection,
              is_success, failure_reason, headline, week_performance):
    cursor = conn.cursor()
    timestamp = datetime.now()
    try:
        cursor.execute("""
            INSERT INTO bitcoin_trades
            (timestamp, decision, percentage, reason, btc_balance, krw_balance,
             btc_avg_buy_price, btc_krw_price, reflection, is_success,
             failure_reason, headline, week_performance)
            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        """, (
            timestamp, decision, percentage, reason, btc_balance, krw_balance,
            btc_avg_buy_price, btc_krw_price, reflection, is_success,
            failure_reason, headline, week_performance
        ))
        conn.commit()
        logger.info("거래 로그 저장 완료")
    except Error as e:
        conn.rollback()
        logger.error(f"거래 로그 저장 실패: {e}")

def get_recent_trades(conn, days=7):
    cursor = conn.cursor()
    seven_days_ago = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d %H:%M:%S')
    try:
        query = "SELECT * FROM bitcoin_trades WHERE timestamp > %s ORDER BY timestamp DESC"
        cursor.execute(query, (seven_days_ago,))
        rows = cursor.fetchall()
        columns = [desc[0] for desc in cursor.description]
        return pd.DataFrame(rows, columns=columns)
    except Error as e:
        logger.error(f"최근 거래내역 조회 실패: {e}")
        return pd.DataFrame()

Step 3. indicators.py - 기술적 분석 시스템

기술적 분석은 자동매매 판단에 매우 중요한 기준입니다.
볼린저 밴드, RSI, MACD, 이동평균선(SMA/EMA) 지표를 적용합니다.

코드

import ta
from ta.utils import dropna

def add_indicators(df):
    indicator_bb = ta.volatility.BollingerBands(close=df['close'], window=20, window_dev=2)
    df['bb_bbm'] = indicator_bb.bollinger_mavg()
    df['bb_bbh'] = indicator_bb.bollinger_hband()
    df['bb_bbl'] = indicator_bb.bollinger_lband()

    df['rsi'] = ta.momentum.RSIIndicator(close=df['close'], window=14).rsi()

    macd = ta.trend.MACD(close=df['close'])
    df['macd'] = macd.macd()
    df['macd_signal'] = macd.macd_signal()
    df['macd_diff'] = macd.macd_diff()

    df['sma_20'] = ta.trend.SMAIndicator(close=df['close'], window=20).sma_indicator()
    df['ema_12'] = ta.trend.EMAIndicator(close=df['close'], window=12).ema_indicator()

    return df

def preprocess_ohlcv(df):
    df = dropna(df)
    df = add_indicators(df)
    return df

사용 예시

import pyupbit

df = pyupbit.get_ohlcv("KRW-BTC", interval="day", count=30)
df = add_indicators(df)
print(df.tail())​

🔜 다음 글

다음 글에서는 OpenAI GPT 모델을 활용하여 거래 회고 작성 및 매수/매도 판단 자동화 시스템을 구현해보겠습니다.