입문7분 분량

자동매매 기초 1편 — 봇은 돈 버는 기계가 아니라 규칙 실행기다

시스템트레이딩 기초 강의 1편 정리본입니다. 자동매매가 실제로 자동화해주는 게 뭔지, 첫 봇을 어디까지 만들면 되는지 코드로 확인합니다.

시작하려는 분들한테서 "뭐부터 손대야 하냐"는 질문을 자주 받았습니다. 그래서 기초 강의 1편을 찍었습니다. 복잡하고 디테일한 건 다 걷어내고 누구나 따라할 수 있는 수준으로, 시스템트레이딩이 뭘 자동화해주는 물건인지만 다뤘습니다. 영상은 동기부여 쪽에 무게를 뒀고, 이 글은 그 정리본에 영상에는 안 넣은 최소 실행 코드를 붙인 것입니다.

자동화되는 건 예측이 아니라 실행이다

자동매매를 시작하는 사람 대부분이 "컴퓨터가 나보다 시장을 잘 읽어줄 것"이라고 기대합니다. 그런데 봇이 실제로 하는 일은 그게 아닙니다. 봇은 내가 정한 규칙을 토씨 하나 안 틀리고 반복 실행할 뿐이에요. 규칙이 엉망이면 봇은 그 엉망인 규칙을 24시간 성실하게 반복해서 돈을 더 빨리 잃습니다. 이게 1탄에서 제일 먼저 짚고 싶었던 부분입니다.

그러면 왜 굳이 자동화하냐. 사람이 구조적으로 못 하는 일이 세 가지 있기 때문입니다.

  • 일관성 — 같은 조건이 100번 나오면 사람은 100번 다르게 반응합니다. 어제 손실 본 다음 날엔 똑같은 신호도 손이 안 나가요. 봇은 100번 다 같은 판단을 합니다. 이건 전략이 좋아진다는 뜻이 아니라, 전략의 성과와 내 심리를 분리해서 측정할 수 있게 된다는 뜻입니다.
  • 지속성 — 코인 시장은 자는 동안에도 돌아갑니다. 사람이 커버할 수 있는 시간대는 하루 중 일부고, 하필 그 밖의 시간에 큰 게 나옵니다.
  • 검증 가능성 — 규칙을 코드로 적어놓으면 과거 데이터에 그대로 돌려볼 수 있습니다. 머릿속에만 있는 감은 검증할 방법이 없어요. 이 검증 가능성이 사실 자동매매의 제일 큰 소득입니다. 돌려보면 대부분의 전략이 생각보다 훨씬 별로라는 걸 알게 되거든요.

최소 구성은 네 덩어리다

봇 구조를 아무리 복잡하게 짜도 결국 이 순서입니다. 데이터를 가져오고(시세), 규칙에 넣어 판단하고(신호), 주문을 내고(체결), 무슨 일이 있었는지 남깁니다(기록). 첫 봇은 이 네 덩어리가 끊기지 않고 한 바퀴 도는 것만 확인하면 됩니다. 전략의 품질은 그다음 문제예요. 아래는 첫 번째와 두 번째 덩어리입니다. 이동평균 교차라는, 일부러 제일 뻔한 규칙을 넣었습니다.

import ccxt
import pandas as pd

# 시세 조회는 공개 엔드포인트다. 여기엔 API 키가 필요 없다
ex = ccxt.binance({"enableRateLimit": True})

# 1시간봉 200개
ohlcv = ex.fetch_ohlcv("BTC/USDT", timeframe="1h", limit=200)
df = pd.DataFrame(ohlcv, columns=["ts", "open", "high", "low", "close", "volume"])

df["fast"] = df["close"].rolling(20).mean()
df["slow"] = df["close"].rolling(60).mean()

# 마지막 행(-1)은 아직 안 닫힌 봉이다. 이걸로 판정하면 값이 계속 흔들리고
# 백테스트 결과와 실매매 동작이 어긋난다. 확정된 직전 봉(-2)으로 판정한다
prev, last = df.iloc[-3], df.iloc[-2]

if prev.fast <= prev.slow and last.fast > last.slow:
    signal = "진입"
elif prev.fast >= prev.slow and last.fast < last.slow:
    signal = "청산"
else:
    signal = "대기"

print(pd.to_datetime(df["ts"].iloc[-2], unit="ms"), signal)

주석으로 달아둔 -2 인덱스 이야기는 넘어가지 마세요. 안 닫힌 봉으로 판단하면 백테스트에선 잘 나오는데 실매매에선 신호가 켜졌다 꺼졌다 하면서 수수료만 나갑니다. 자동매매 입문자가 처음 만나는 벽이 대개 전략이 아니라 이런 종류의 시점 오류입니다.

첫 주문은 테스트넷에서, 수량은 손실 기준으로

신호가 나왔으면 주문을 냅니다. 바이낸스는 테스트넷을 제공하고 ccxt는 set_sandbox_mode 한 줄로 거기에 붙습니다. 실계좌로 첫 봇을 돌리는 건 그냥 돈 내고 디버깅하는 겁니다. 그리고 수량 — "0.01 BTC씩" 같은 고정 수량 말고, 손절이 걸렸을 때 잃을 금액을 먼저 정하고 거기서 수량을 역산하세요. 자동매매에서 계좌를 지키는 건 진입 규칙이 아니라 이 계산식입니다.

import os
import ccxt

# 키는 환경변수로만 읽는다. 미설정이면 기본값으로 넘어가지 말고 여기서 죽어야 한다
ex = ccxt.binance({
    "apiKey": os.environ["BINANCE_TESTNET_KEY"],
    "secret": os.environ["BINANCE_TESTNET_SECRET"],
    "enableRateLimit": True,
})
ex.set_sandbox_mode(True)  # 실계좌가 아니라 테스트넷으로 라우팅

SYMBOL = "BTC/USDT"
RISK_PER_TRADE = 0.005   # 1회 거래에 잔고의 0.5%까지만 위험에 노출
STOP_PCT = 0.02          # 진입가 대비 2% 손절

balance = ex.fetch_balance()["USDT"]["free"]
price = ex.fetch_ticker(SYMBOL)["last"]

# 손절에 걸렸을 때 잃는 금액이 잔고의 0.5%가 되도록 수량을 역산
amount = (balance * RISK_PER_TRADE) / (price * STOP_PCT)
amount = float(ex.amount_to_precision(SYMBOL, amount))  # 거래소 최소단위로 맞춤

# 역산한 수량이 거래소 최소 주문금액에 못 미치면 주문이 그냥 거부된다
ex.load_markets()
min_notional = ex.market(SYMBOL)["limits"]["cost"]["min"]
if min_notional and amount * price < min_notional:
    raise SystemExit(f"주문금액 미달: {amount * price:.2f} < {min_notional}")

if signal == "진입":  # 위 블록에서 계산한 signal을 그대로 이어 쓴다
    order = ex.create_market_buy_order(SYMBOL, amount)
    print(order["id"], amount)
API 키는 만들 때 출금 권한을 반드시 끄고, IP 화이트리스트를 걸어두세요. 키를 코드에 직접 적거나 깃에 올리면 봇이 아니라 남이 내 계좌를 자동매매합니다. 공개 저장소에 올라간 거래소 키는 사람이 아니라 스캐너 봇이 먼저 찾아냅니다. 키가 한 번이라도 노출됐다고 의심되면 고민하지 말고 거래소에서 즉시 폐기하고 새로 발급하세요.

왜 이게 실전에서 깨지는가

  • 위 이동평균 교차 코드는 동작 구조를 보여주려고 넣은 것이지 수익 전략이 아닙니다. 이 정도로 널리 알려진 규칙은 이미 시장에 반영돼 있다고 보는 게 맞고, 실제로 돌려보면 횡보장에서 신호가 계속 뒤집히며 수수료로 녹습니다. 2탄부터는 이런 걸 검증하는 과정을 다룰 겁니다.
  • 테스트넷에서 잘 돌았다고 실계좌에서 같지 않습니다. 테스트넷은 호가창이 얇고 체결이 비현실적으로 잘 됩니다. 슬리피지, 부분 체결, 주문 거부는 실계좌에서만 만납니다.
  • 봇이 켜져 있다는 것과 봇이 돈을 벌고 있다는 건 완전히 다른 상태입니다. 네트워크 끊김, API 레이트리밋, 거래소 점검으로 봇은 조용히 멈춰 있을 수 있어요. 로그와 알림을 안 붙이면 이틀 뒤에야 알게 됩니다.
  • 자동화한다고 손실이 줄지 않습니다. 감정으로 인한 손실이 규칙에 의한 손실로 바뀔 뿐이고, 규칙이 나쁘면 손실은 더 빠르고 일정하게 납니다. 자동매매의 실익은 그 손실의 원인을 숫자로 추적할 수 있게 된다는 것뿐입니다.
  • 이 글과 첨부 코드는 시스템트레이딩 구조를 설명하려고 만든 교육·연구 자료입니다. 특정 종목이나 매매를 권하지 않고, 어떤 수익도 보장하지 않습니다. 실계좌 운용은 본인 판단과 책임으로 하세요.

첨부파일

영상에 사용된 소스코드와 설명서입니다. 로그인 없이 받을 수 있습니다.

첫 자동매매 봇 최소 구성 소스코드first_bot_skeleton.py · 6.4 KB바이낸스 테스트넷 세팅 가이드binance_testnet_setup.md · 4.1 KB입문자 체크리스트starter_checklist.md · 2.3 KB