상세 컨텐츠

본문 제목

빗썸 API 참여 이벤트로 돈버는 초간단 방법 공유 (신규가입 7만원 이벤트와 중복가능)

일상꿀팁

by 빽꼼이 2026. 4. 30. 18:02

본문

[2026년 5월] 빗썸 파이썬 자동매매 봇 무료 공유

API 수수료 페이백 혜택으로 비용 0원 자동매매 구축하기
+ 신규 가입 7만원 받아서 투자 시드로 활용하세요!

안녕하세요! 최근 코인 시장 변동성이 커지면서 24시간 대응이 가능한 '자동매매'에 관심을 가지는 분들이 많습니다.

마침 빗썸에서 API 거래 수수료를 환급(페이백)해주는 혜택을 진행하고 있어, 수수료 부담 없이 자동매매 봇을 돌리기 가장 좋은 시기입니다. 코딩을 몰라도 누구나 딸깍 한 번으로 실행할 수 있는 초간단 파이썬 자동매매 프로그램과 함께, 시드머니 7만원을 공짜로 얻는 팁까지 정리해 드립니다.


봇을 돌리기 전, 시드머니(7만원)부터 챙기세요

1. 아직 빗썸 계좌가 없다면?

내 돈 넣고 봇을 돌릴 필요 없습니다. 신규 가입 시 즉시 7만원을 받을 수 있으니, 이 돈을 봇의 시드머니로 활용하세요.

빗썸 신규가입 7만원 받으러 가기 →

2. 이미 가입은 완료했다면?

시드머니가 준비되었다면, 수수료 페이백 혜택을 받고 바로 자동매매 봇 세팅을 시작하시면 됩니다.

아래 본문을 계속 읽어주세요 ↓

❓ 왜 하필 빗썸에서 자동매매를 할까?

자동매매(API) 봇을 돌릴 때 가장 무서운 것이 바로 '거래 수수료'입니다. 봇이 하루에도 수십 번씩 사고팔기를 반복하면 수익보다 수수료가 더 크게 나가는 배보다 배꼽이 더 큰 상황이 발생하죠.

하지만 현재 빗썸에서는 API 거래 시 수수료를 환급해 주는 혜택을 제공하고 있어, 사실상 수수료 0원으로 시스템 트레이딩 환경을 구축할 수 있습니다. 초보자가 자동매매를 연습하기에 이보다 완벽한 조건은 없습니다. 더구나 내가 설정한 자동매매가 만약 돈을 잃지 아주 약간의 이득이라도 볼 수 있다면, 해당 거래에서 발생한 거래 수수료를 쌓아서 환급받을 수 있습니다. 최대 1000억까지 환급해준다고 하니깐 몇 가지 연구를 통해 최대한 많은 환급금을 받을 수 있도록 노력해보세요.


🚀 빗썸 파이썬 자동매매 봇 세팅 가이드

1단계 : 빗썸 신규가입 (초기 시드 7만원 확보)

앞서 말씀드렸듯, 아직 가입 전이라면 제발 내 생돈 넣지 마시고 신규 가입 7만원 혜택을 먼저 챙겨서 시드로 쓰세요. 가입 없이 API부터 건드리면 7만원이 누락될 수 있으니 아래 링크를 먼저 확인해 주세요.

👉 [필독] 빗썸 가입하고 투자 지원금 7만원 받는 법


2단계 : API 이벤트 참여 버튼 누르기

수수료 페이백을 받기 위해 빗썸 이벤트 페이지에 접속하여 [API 거래 이벤트]에서 '참여하기' 버튼을 필수로 눌러주세요.

공지사항 - No.1 가상자산 플랫폼, 빗썸


3단계 : API 키 발급받기 (※보안 주의)

마이페이지의 [API 관리] 메뉴로 들어가서 봇과 연결할 API Key를 발급받습니다.

🚨 [절대 주의사항]
1. 발급받은 API 키는 절대 타인에게 공유하거나 인터넷(깃허브 등)에 노출하면 안 됩니다.
2. 권한 설정 시 '출금/이체하기' 기능은 반드시 체크 해제(비활성화)하시고, 오직 '조회'와 '거래' 권한만 부여하세요!

 


4단계 : (초보/개발자용) 자동매매 프로그램 실행

이제 발급받은 API 키를 프로그램에 넣고 빗썸 서버와 연결할 차례입니다. 파이썬이 익숙한 분들은 아래 코드를 복사해서 쓰시면 되고, 코딩을 전혀 모르는 초보자분들은 제가 만들어둔 원클릭 실행 프로그램을 다운로드해서 사용하시면 됩니다.

🟢 코딩을 모르는 초보자라면? (가장 추천)

복잡한 파이썬 설치 과정 없이 바로 실행할 수 있도록 세팅해 둔 파일을 첨부합니다. 압축을 풀고 클릭만 하시면 됩니다. 

  1. 아래 첨부된 파일을 다운로드하고 압축을 풉니다.
  2. 파일을 열고 3단계에서 발급받은 본인의 API Key 2개를 입력칸에 붙여넣습니다. (참고로 라이선스 키는 CS951LF 입니다)
  3. [실행] 버튼을 누르면 자동으로 잔고 조회 및 매매 로직이 돌아갑니다.
⌨️ 파이썬(Python)을 다룰 줄 아는 분이라면?

라이브러리(pip install pybithumb) 설치 후, 아래 기본 코드를 바탕으로 본인만의 전략(이동평균선 등)을 추가해 보세요.

"""
Bithumb 스캐너 봇 v6.0 (특정 코인 지정 기능 추가)
- 기능 1: '지정 코인' 입력란에 티커(예: XRP)를 입력하면 해당 코인만 집중 공략
- 기능 2: 입력란을 비워두면 기존처럼 전 종목 스캔
- 로직: v5.9의 검증된 매수/매도 로직 유지
"""

import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import threading
import time
from datetime import datetime
import math
import pybithumb
import pandas as pd
import requests

class BithumbScannerBot:
    
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("빗썸 스캐너 v6.0 (타겟 지정 가능)")
        self.root.geometry("950x950")
        
        self.is_running = False
        self.connect_key = tk.StringVar()
        self.secret_key = tk.StringVar()
        self.password_input = tk.StringVar()
        
        # 설정 변수
        self.ma_interval = tk.StringVar(value="1h")      
        self.ma_short_val = tk.StringVar(value="5")      
        self.ma_long_val = tk.StringVar(value="90")      
        
        self.rsi_interval = tk.StringVar(value="5m")     
        self.rsi_buy_cond = tk.StringVar(value="40")     
        
        self.buy_amount_krw = tk.StringVar(value="5500") 
        self.max_slots = tk.StringVar(value="3")
        self.trailing_gap = tk.StringVar(value="3.0")
        
        # [NEW] 타겟 코인 변수
        self.target_ticker = tk.StringVar(value="") 
        
        self.current_scan_coin = tk.StringVar(value="대기 중...")
        self.total_profit_status = tk.StringVar(value="총 매수: 0원 | 평가: 0원 | 수익률: 0.00%")
        
        self.held_coins = {} 
        self.bithumb = None
        self.log_text = None
        self.last_monitor_msg_time = 0
        
        self.setup_gui()

    def setup_gui(self):
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill="both", expand=True)

        # 1. 인증
        auth_frame = ttk.LabelFrame(main_frame, text="1. API 및 인증", padding="5")
        auth_frame.pack(fill="x", pady=5)
        
        input_frame = ttk.Frame(auth_frame)
        input_frame.pack(fill="x")
        ttk.Label(input_frame, text="라이센스 키:").pack(side="left")
        ttk.Entry(input_frame, textvariable=self.password_input, width=15).pack(side="left", padx=5)
        ttk.Button(input_frame, text="인증확인", command=self.verify_password).pack(side="left")
        
        api_frame = ttk.Frame(auth_frame)
        api_frame.pack(fill="x", pady=5)
        ttk.Label(api_frame, text="Connect Key:").pack(anchor="w")
        ttk.Entry(api_frame, textvariable=self.connect_key, width=50, show="*").pack(anchor="w")
        ttk.Label(api_frame, text="Secret Key:").pack(anchor="w")
        ttk.Entry(api_frame, textvariable=self.secret_key, width=50, show="*").pack(anchor="w")

        # 2. 설정
        rule_frame = ttk.LabelFrame(main_frame, text="2. 전략 설정 (MA 추세 + RSI 타점)", padding="5")
        rule_frame.pack(fill="x", pady=5)
        
        grid_frame = ttk.Frame(rule_frame)
        grid_frame.pack(fill="x")
        
        valid_intervals = ['1m', '3m', '5m', '10m', '30m', '1h', '6h', '12h', '24h']
        
        # MA 설정
        ttk.Label(grid_frame, text="[MA 설정]", foreground="blue").grid(row=0, column=0, sticky="w", padx=5)
        ttk.Label(grid_frame, text="기준봉:").grid(row=0, column=1, sticky="w")
        self.ma_combo = ttk.Combobox(grid_frame, textvariable=self.ma_interval, values=valid_intervals, width=5)
        self.ma_combo.grid(row=0, column=2, sticky="w")
        ttk.Label(grid_frame, text="단기이평:").grid(row=0, column=3, sticky="w", padx=5)
        ttk.Entry(grid_frame, textvariable=self.ma_short_val, width=4).grid(row=0, column=4, sticky="w")
        ttk.Label(grid_frame, text="장기이평:").grid(row=0, column=5, sticky="w", padx=5)
        ttk.Entry(grid_frame, textvariable=self.ma_long_val, width=4).grid(row=0, column=6, sticky="w")
        
        # RSI 설정
        ttk.Label(grid_frame, text="[RSI 설정]", foreground="red").grid(row=1, column=0, sticky="w", padx=5, pady=5)
        ttk.Label(grid_frame, text="기준봉:").grid(row=1, column=1, sticky="w")
        self.rsi_combo = ttk.Combobox(grid_frame, textvariable=self.rsi_interval, values=valid_intervals, width=5)
        self.rsi_combo.grid(row=1, column=2, sticky="w")
        ttk.Label(grid_frame, text="매수값:").grid(row=1, column=3, sticky="w", padx=5)
        ttk.Entry(grid_frame, textvariable=self.rsi_buy_cond, width=4).grid(row=1, column=4, sticky="w")
        ttk.Label(grid_frame, text="이하").grid(row=1, column=5, sticky="w")
        
        # [NEW] 타겟 설정 및 자금
        ttk.Label(grid_frame, text="[타겟/자금]", foreground="green").grid(row=2, column=0, sticky="w", padx=5, pady=5)
        
        # 지정 코인 입력란
        ttk.Label(grid_frame, text="지정 코인:").grid(row=2, column=1, sticky="w")
        ttk.Entry(grid_frame, textvariable=self.target_ticker, width=6).grid(row=2, column=2, sticky="w")
        ttk.Label(grid_frame, text="(비우면 전체)").grid(row=2, column=3, sticky="w")
        
        ttk.Label(grid_frame, text="매수금액:").grid(row=3, column=1, sticky="w")
        ttk.Entry(grid_frame, textvariable=self.buy_amount_krw, width=8).grid(row=3, column=2, sticky="w")
        
        ttk.Label(grid_frame, text="최대 보유:").grid(row=3, column=3, sticky="w", padx=5)
        ttk.Entry(grid_frame, textvariable=self.max_slots, width=4).grid(row=3, column=4, sticky="w")
        
        ttk.Label(grid_frame, text="트레일링%:").grid(row=3, column=5, sticky="w", padx=5)
        ttk.Entry(grid_frame, textvariable=self.trailing_gap, width=4).grid(row=3, column=6, sticky="w")

        # 3. 현황
        status_frame = ttk.LabelFrame(main_frame, text="3. 포트폴리오 현황", padding="10")
        status_frame.pack(fill="x", pady=10)
        self.scan_label = ttk.Label(status_frame, textvariable=self.current_scan_coin, 
                                   font=("Arial", 11), foreground="blue", anchor="center")
        self.scan_label.pack(fill="x", pady=(0, 5))
        self.total_profit_label = ttk.Label(status_frame, textvariable=self.total_profit_status,
                                           font=("Arial", 14, "bold"), foreground="darkgreen", anchor="center",
                                           background="#f0f0f0")
        self.total_profit_label.pack(fill="x", ipady=8)

        # 4. 버튼
        btn_frame = ttk.Frame(main_frame)
        btn_frame.pack(fill="x", pady=5)
        self.start_btn = ttk.Button(btn_frame, text="🚀 스캔 시작", command=self.start_scan, state="disabled")
        self.start_btn.pack(side="left", expand=True, fill="x", padx=2)
        self.stop_btn = ttk.Button(btn_frame, text="🛑 정지", command=self.stop_scan, state="disabled")
        self.stop_btn.pack(side="left", expand=True, fill="x", padx=2)

        # 5. 로그
        log_frame = ttk.LabelFrame(main_frame, text="4. 상세 로그", padding="5")
        log_frame.pack(fill="both", expand=True)
        self.log_text = scrolledtext.ScrolledText(log_frame, height=15, font=("Consolas", 9))
        self.log_text.pack(fill="both", expand=True)

    # --- 유틸리티 ---
    def add_log(self, msg):
        self.root.after(0, self._insert_log, msg)

    def _insert_log(self, msg):
        ts = datetime.now().strftime("%H:%M:%S")
        self.log_text.insert(tk.END, f"[{ts}] {msg}\n")
        self.log_text.see(tk.END)
        if self.log_text.get("1.0", tk.END).count('\n') > 2000:
            self.log_text.delete("1.0", "100.0")

    def verify_password(self):
        if self.password_input.get():
            messagebox.showinfo("성공", "인증되었습니다.")
            self.start_btn.config(state="normal")
        else:
            messagebox.showerror("오류", "키 입력 필요")

    # --- 데이터 조회 ---
    def get_ohlcv_data(self, ticker: str, interval: str) -> pd.DataFrame or None:
        symbol = f"{ticker}_KRW"
        url = f"https://api.bithumb.com/public/candlestick/{symbol}/{interval}"
        try:
            headers = {"accept": "application/json"}
            response = requests.get(url, headers=headers, timeout=3)
            data = response.json()
            if data.get('status') != '0000': return None
            df = pd.DataFrame(data.get('data', []), columns=['time', 'open', 'close', 'high', 'low', 'volume'])
            df['time'] = pd.to_datetime(df['time'], unit='ms')
            df = df.set_index('time')
            return df[['open', 'high', 'low', 'close']].astype(float) 
        except: return None

    # --- 봇 제어 ---
    def start_scan(self):
        if not self.connect_key.get(): messagebox.showerror("오류", "API 키 필요"); return
        try:
            self.bithumb = pybithumb.Bithumb(self.connect_key.get(), self.secret_key.get())
        except: messagebox.showerror("오류", "API 객체 생성 실패"); return
        
        self.is_running = True
        self.start_btn.config(state="disabled")
        self.stop_btn.config(state="normal")
        self.ma_combo.config(state="disabled") 
        self.rsi_combo.config(state="disabled")
        
        threading.Thread(target=self.run_scanning_loop, daemon=True).start()

    def stop_scan(self):
        self.is_running = False
        self.start_btn.config(state="normal")
        self.stop_btn.config(state="disabled")
        self.ma_combo.config(state="normal")
        self.rsi_combo.config(state="normal")
        self.current_scan_coin.set("🛑 정지됨")
        self.add_log("스캔 정지 요청됨.")

    def run_scanning_loop(self):
        ma_int = self.ma_interval.get()
        rsi_int = self.rsi_interval.get()
        
        # [NEW] 타겟 설정 확인
        target_coin = self.target_ticker.get().strip().upper()
        
        if target_coin:
            self.add_log(f"=== 🎯 지정 코인 감시 시작: {target_coin} (MA:{ma_int} / RSI:{rsi_int}) ===")
        else:
            self.add_log(f"=== 🔍 전체 스캔 시작 (MA:{ma_int} / RSI:{rsi_int}) ===")
        
        while self.is_running:
            try:
                self.manage_held_coins()
                
                max_slots = int(self.max_slots.get())
                held_list = list(self.held_coins.keys())
                
                # 슬롯 체크
                if len(self.held_coins) >= max_slots:
                    status_text = f"🔒 슬롯 가득 참 (보유중: {', '.join(held_list)})"
                    self.current_scan_coin.set(status_text)
                    if time.time() - self.last_monitor_msg_time > 30:
                        self.add_log(f"👀 슬롯 가득 참. 보유 종목 집중 감시 중... {held_list}")
                        self.last_monitor_msg_time = time.time()
                    time.sleep(1)
                    continue 

                # [NEW] 타겟이 있으면 그것만, 없으면 전체
                if target_coin:
                    all_tickers = [target_coin]
                else:
                    all_tickers = pybithumb.get_tickers()
                
                total = len(all_tickers)
                
                for idx, ticker in enumerate(all_tickers):
                    if not self.is_running: break
                    if ticker in self.held_coins: continue 
                    
                    if target_coin:
                        self.current_scan_coin.set(f"🎯 타겟 감시 중: {ticker}")
                    else:
                        self.current_scan_coin.set(f"🔍 확인 중 ({idx+1}/{total}): {ticker}")
                    
                    if len(self.held_coins) >= max_slots: break

                    # API 딜레이 (타겟 지정시는 조금 더 자주 봐도 됨)
                    delay = 0.5 if target_coin else 0.15
                    time.sleep(delay) 
                    
                    self.process_ticker(ticker, ma_int, rsi_int)
                
                if self.is_running and not target_coin:
                    self.add_log("💤 전체 스캔 완료. 5초 대기...")
                    time.sleep(5)
                
            except Exception as e:
                self.add_log(f"메인 루프 에러: {e}")
                time.sleep(5)

    def process_ticker(self, ticker, ma_int, rsi_int):
        try:
            ma_short_p = int(self.ma_short_val.get())
            ma_long_p = int(self.ma_long_val.get())
            rsi_threshold = float(self.rsi_buy_cond.get())

            df_ma = self.get_ohlcv_data(ticker, ma_int)
            if df_ma is None or len(df_ma) < ma_long_p + 2: return
            
            if ma_int == rsi_int:
                df_rsi = df_ma
            else:
                df_rsi = self.get_ohlcv_data(ticker, rsi_int)
                if df_rsi is None: return
            
            if len(df_rsi) < 16: return

            ma_short = df_ma['close'].rolling(window=ma_short_p).mean().iloc[-1]
            ma_long = df_ma['close'].rolling(window=ma_long_p).mean().iloc[-1]
            
            delta = df_rsi['close'].diff(1)
            gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
            loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
            rs = gain / loss
            rsi_val = 100 - (100 / (1 + rs))
            
            cur_price = df_rsi['close'].iloc[-1]
            rsi_now = rsi_val.iloc[-1]
            
            if pd.isna(ma_short) or pd.isna(ma_long) or pd.isna(rsi_now): return

            cond_ma = ma_short > ma_long    
            cond_rsi = rsi_now <= rsi_threshold      
            
            mark_ma = "✅" if cond_ma else "❌"
            mark_rsi = "✅" if cond_rsi else "❌"
            
            status_msg = f"{ticker} | {ma_int}MA({ma_short_p}/{ma_long_p}):{mark_ma} | {rsi_int}RSI:{rsi_now:.1f}{mark_rsi}"
            
            if cond_ma and cond_rsi:
                self.add_log(f"⚡ [BUY] {status_msg}")
                self.execute_buy(ticker)
            elif cond_ma or cond_rsi:
                self.add_log(f"👀 [관심] {status_msg}")

        except Exception:
            pass

    # --- [매수 로직] Test 코드와 동일 ---
    def execute_buy(self, ticker):
        try:
            balance = self.bithumb.get_balance(ticker)
            if balance is None: return
            coin_before = float(balance[0])
            
            orderbook = pybithumb.get_orderbook(ticker)
            if not orderbook: return
            ask_price = float(orderbook['asks'][0]['price']) 
            
            krw_limit = int(self.buy_amount_krw.get())
            safe_krw = krw_limit * 0.9975 
            
            buy_qty = safe_krw / ask_price
            buy_qty = math.floor(buy_qty * 10000) / 10000 
            
            if buy_qty <= 0: 
                self.add_log(f"⚠️ {ticker} 계산된 수량 0")
                return

            self.add_log(f"🛒 {ticker} 매수 시도: {buy_qty}개 (@{ask_price})")
            
            self.bithumb.buy_market_order(ticker, buy_qty)
            time.sleep(3)
            
            balance_new = self.bithumb.get_balance(ticker)
            coin_after = float(balance_new[0])
            diff = coin_after - coin_before
            
            if diff > 0:
                self.held_coins[ticker] = {
                    'buy_price': ask_price, 
                    'qty': diff,
                    'highest_price': ask_price 
                }
                self.add_log(f"✅ {ticker} 매수 체결 완료! (+{diff}개)")
            else:
                self.add_log(f"❌ {ticker} 미체결 (잔고변화 없음)")
                
        except Exception as e:
            self.add_log(f"❌ 매수 에러: {e}")

    # --- 트레일링 스탑 ---
    def manage_held_coins(self):
        if not self.held_coins: 
            self.total_profit_status.set("총 매수: 0원 | 평가: 0원 | 수익률: 0.00%")
            return
        
        trailing_gap_pct = float(self.trailing_gap.get())
        total_buy_val = 0
        total_curr_val = 0
        
        for ticker in list(self.held_coins.keys()):
            try:
                curr = pybithumb.get_current_price(ticker)
                if curr is None: continue 
                
                buy_price = self.held_coins[ticker]['buy_price']
                highest = self.held_coins[ticker]['highest_price']
                qty = self.held_coins[ticker]['qty']
                
                total_buy_val += (buy_price * qty)
                total_curr_val += (curr * qty)
                
                if curr > highest:
                    self.held_coins[ticker]['highest_price'] = curr
                    highest = curr
                
                profit_rate = (curr - buy_price) / buy_price * 100
                drop_from_high = (curr - highest) / highest * 100
                
                if drop_from_high <= -trailing_gap_pct:
                    self.execute_sell(ticker, qty, f"트레일링({drop_from_high:.2f}%)", profit_rate)
                elif profit_rate <= -3.0: 
                    self.execute_sell(ticker, qty, f"손절({profit_rate:.2f}%)", profit_rate)
                    
            except: pass
            
        if total_buy_val > 0:
            total_rate = (total_curr_val - total_buy_val) / total_buy_val * 100
            status_str = f"총 매수: {total_buy_val:,.0f}원 | 평가: {total_curr_val:,.0f}원 | 수익률: {total_rate:+.2f}%"
            self.total_profit_status.set(status_str)

    def execute_sell(self, ticker, qty, reason, final_profit):
        try:
            self.add_log(f"👋 {ticker} 매도 실행 [{reason}] (수익: {final_profit:.2f}%)")
            self.bithumb.sell_market_order(ticker, qty)
            time.sleep(1)
            if ticker in self.held_coins:
                del self.held_coins[ticker]
            self.add_log(f"✅ {ticker} 매도 완료.")
        except Exception as e:
            self.add_log(f"❌ 매도 에러: {e}")

if __name__ == "__main__":
    BithumbScannerBot().root.mainloop()

 

 


코인 시장에서는 감정을 배제한 기계적인 매매가 승률을 높이는 지름길입니다. 이번 빗썸 수수료 페이백 기간을 활용해 무료로 자동매매 시스템을 경험해 보시고, 가입 지원금 7만원도 꼭 시드로 알차게 활용하시길 바랍니다.

내용이 도움이 되셨다면 공감과 댓글 부탁드리며, 프로그램 사용 중 막히는 부분이 있다면 언제든 댓글 남겨주세요!

관련글 더보기