월 0원으로 돌리는 24시간 코인 자동매매 (N100 + Python)
1. 서론: 24시간 잠들지 않는 나만의 코인 매매 엔진
코인 시장은 24시간 돌아가며 급변합니다. 개인 투자자가 이 모든 흐름을 쫓기란 불가능하죠. 저는 저전력 가성비 서버인 N100 리눅스 서버를 활용해 바이낸스와 비트겟의 현물/선물 시장을 동시에 공략하는 4트랙 통합 매매 시스템을 구축했습니다.
2. 프로젝트 구조 (Directory Structure)
관리가 쉽고 확장이 용이하도록 기능을 모듈별로 분리했습니다. 아래 구조대로 파일을 생성해 주세요.
Plaintext
~/Projects/crypto_bot/
├── config/
│ └── settings.py # API 키 관리 및 봇별 환경 설정
├── core/
│ ├── base_bot.py # 코인 전용 실행 엔진 (CCXT 기반)
│ └── strategy.py # EMA 추세 추종 전략 엔진
├── utils/
│ └── notifier.py # 텔레그램 알림 모듈
├── logs/ # 로그 파일 저장소
├── main.py # 4개 트랙 통합 실행 엔트리 포인트
└── ecosystem.config.js # PM2 자동 실행 및 환경 변수 설정
3. 모듈별 풀 소스코드 (Modular Full Source)
① config/settings.py (환경 설정)
Python
import os
# 실행 모드: 'testnet' 또는 'production'
BOT_MODE = os.environ.get('BOT_MODE', 'testnet')
TG_TOKEN = os.environ.get('TG_TOKEN', '') # 환경변수 설정 권장
TG_CHAT_ID = os.environ.get('TG_CHAT_ID', '') # 환경변수 설정 권장
# 4개 트랙 설정 (Binance Spot/Future, Bitget Spot/Future)
TRACK_CONFIGS = {
'BN_FUT': {'exchange': 'binance', 'type': 'future', 'symbol': 'BTC/USDT'},
'BN_SPT': {'exchange': 'binance', 'type': 'spot', 'symbol': 'BTC/USDT'},
'BG_FUT': {'exchange': 'bitget', 'type': 'future', 'symbol': 'ETH/USDT'},
'BG_SPT': {'exchange': 'bitget', 'type': 'spot', 'symbol': 'ETH/USDT'}
}
# 매매 파라미터
STR_SETTINGS = {
'ratio': 0.1, # 가용 잔고의 10% 사용
'interval': 15, # 분석 주기 (초)
'ema_short': 20,
'ema_long': 60
}
② core/strategy.py (전략 로직)
Python
import pandas_ta as ta
import pandas as pd
class StrategyEngine:
@staticmethod
def calculate_ema_strategy(df):
"""
전략: EMA 20/60 골든크로스 & ATR 변동성 손익비 전략
- 15분 봉 기준 정배열 초입 진입
- 손익비 1:2 (ATR 기반)
"""
if len(df) < 70: return None, 0, 0, 0
# 지표 계산
df['ema20'] = ta.ema(df['close'], length=20)
df['ema60'] = ta.ema(df['close'], length=60)
df['atr'] = ta.atr(df['high'], df['low'], df['close'], length=14)
last = df.iloc[-1]
prev = df.iloc[-2]
curr_p = float(last['close'])
atr_v = float(last['atr'])
# 골든크로스 조건: 60선 위에서 20선을 돌파할 때
if last['ema20'] > last['ema60'] and prev['close'] < last['ema20'] < curr_p:
sl = curr_p - (atr_v * 2) # 손절: ATR 2배
tp = curr_p + (atr_v * 4) # 익절: ATR 4배
return "LONG", curr_p, sl, tp
return None, 0, 0, 0
③ core/base_bot.py (매매 실행 엔진)
Python
import asyncio
import ccxt.async_support as ccxt
import pandas as pd
import os
from core.strategy import StrategyEngine
from config.settings import BOT_MODE, STR_SETTINGS
class CryptoBot:
def __init__(self, bot_id, cfg):
self.bot_id = bot_id
self.cfg = cfg
self.current_pos = None
# CCXT 거래소 초기화
self.ex = getattr(ccxt, cfg['exchange'])({
'apiKey': os.environ.get(f"{bot_id}_KEY"),
'secret': os.environ.get(f"{bot_id}_SECRET"),
'enableRateLimit': True,
'options': {'defaultType': cfg['type']}
})
if BOT_MODE == 'testnet': self.ex.set_sandbox_mode(True)
async def fetch_data(self):
"""15분 봉 OHLCV 데이터 수집"""
ohlcv = await self.ex.fetch_ohlcv(self.cfg['symbol'], timeframe='15m', limit=100)
return pd.DataFrame(ohlcv, columns=['t','o','h','l','c','v'])
async def run_loop(self):
print(f"🚀 [{self.bot_id}] 모니터링 시작: {self.cfg['symbol']}")
while True:
try:
if not self.current_pos:
df = await self.fetch_data()
side, price, sl, tp = StrategyEngine.calculate_ema_strategy(df)
if side:
print(f"🎯 [{self.bot_id}] {side} 시그널 포착: {price}")
# 실제 주문 로직 예시 (시장가 진입)
# order = await self.ex.create_market_order(self.cfg['symbol'], 'buy', amount)
self.current_pos = {'side': side, 'sl': sl, 'tp': tp}
# 포지션이 있을 경우 SL/TP 감시 로직 추가 가능
await asyncio.sleep(STR_SETTINGS['interval'])
except Exception as e:
print(f"🚨 [{self.bot_id}] 에러 발생: {e}")
await asyncio.sleep(30)
④ main.py (통합 엔트리 포인트)
Python
import asyncio
from config.settings import TRACK_CONFIGS
from core.base_bot import CryptoBot
async def main():
tasks = []
# 4개 트랙(BN_FUT, BN_SPT, BG_FUT, BG_SPT) 동시 실행
for bot_id, cfg in TRACK_CONFIGS.items():
bot = CryptoBot(bot_id, cfg)
tasks.append(bot.run_loop())
print(f"✅ 총 {len(tasks)}개 트랙 병렬 가동 중...")
await asyncio.gather(*tasks)
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n👋 사용자에 의해 시스템이 종료되었습니다.")
utils/notifier.py (알림 모듈)
Python
# utils/notifier.py
import aiohttp
import asyncio
from config.settings import TG_TOKEN, TG_CHAT_ID
class TelegramNotifier:
def __init__(self):
self.token = TG_TOKEN
self.chat_id = TG_CHAT_ID
self.api_url = f"https://api.telegram.org/bot{self.token}/sendMessage"
async def send_message(self, text):
"""텔레그램 메시지 비동기 전송"""
if not self.token or not self.chat_id:
print("⚠️ [알림] 텔레그램 설정이 누락되었습니다.")
return
payload = {
"chat_id": self.chat_id,
"text": text,
"parse_mode": "HTML"
}
try:
async with aiohttp.ClientSession() as session:
async with session.post(self.api_url, json=payload) as response:
if response.status != 200:
print(f"❌ [알림] 전송 실패: {await response.text()}")
except Exception as e:
print(f"🚨 [알림] 네트워크 에러: {e}")
# 싱글톤 패턴으로 인스턴스 제공
notifier = TelegramNotifier()
4. 실제 운영 메뉴얼 (Manual)
1단계: 환경 설정
N100 서버의 프로젝트 폴더에서 가상환경을 잡고 필수 패키지를 설치합니다.
Bash
python3 -m venv venv
source venv/bin/activate
pip install ccxt pandas pandas-ta
mkdir logs
2단계: PM2 설정 (ecosystem.config.js)
서버 재부팅 시에도 자동으로 봇이 살아나도록 설정합니다.
JavaScript
module.exports = {
apps: [{
name: "crypto-4track-bot",
script: "./main.py",
interpreter: "./venv/bin/python3",
env: {
BOT_MODE: "testnet",
PYTHONPATH: ".",
BN_FUT_KEY: "발급받은키",
BN_FUT_SECRET: "발급받은시크릿"
// 나머지 트랙의 키도 여기에 추가하거나 서버 환경변수에 등록하세요.
}
}]
}
실행: pm2 start ecosystem.config.js && pm2 save
3단계: 관리 및 모니터링
- 상태 확인:
pm2 status - 실시간 로그:
pm2 logs crypto-4track-bot - 에러만 보기:
tail -f logs/err.log | grep "Error"
5. 마치며: 자동화가 주는 심리적 안정감
이 시스템은 감정을 배제하고 기계적인 매매를 수행합니다. 모듈화된 설계를 통해 전략을 한곳(strategy.py)에서만 수정하면 4개 트랙에 즉시 반영되는 효율성을 갖췄습니다. N100의 저전력 환경에서 여러분만의 든든한 코인 트레이더를 가동해 보세요!
면책조항: 본 포스팅의 코드는 학습용 샘플이며, 실제 투자의 결과는 투자자 본인에게 있습니다. 반드시 테스트넷에서 충분한 검증을 거치시길 바랍니다.