Chuyển tới nội dung chính

🐍 Ngày 44 Python 365 ngày | Xây dựng bot giao dịch tự động với Binance

🗓 Ngày 44: Bot giao dịch tự động đầu tiên của bạn​

Sau 43 ngày, bạn đã biết cách lấy dữ liệu giá, đọc order book, xử lý dữ liệu giao dịch bằng pandas. Hôm nay chúng ta ghép tất cả lại thành một bot giao dịch tự động thật sự — thứ có thể tự đọc giá, tự quyết định và tự đặt lệnh mà không cần bạn ngồi trước màn hình.

⚠️ Nguyên tắc an toàn số 1: Toàn bộ bài học này chạy trên Binance Testnet (tiền ảo, không phải tiền thật). Chỉ khi bot đã chạy ổn định nhiều tuần trên testnet, bạn mới nên nghĩ đến tiền thật — và khi đó hãy bắt đầu với số vốn nhỏ nhất có thể.


🎯 Mục tiêu bài học​

Sau bài này, bạn sẽ:

  • Hiểu kiến trúc tổng thể của một bot giao dịch tự động.
  • Kết nối được Binance API bằng thư viện python-binance.
  • Đặt được market order và limit order bằng code Python.
  • Đọc được số dư tài khoản và trạng thái lệnh.
  • Xây dựng vòng lặp bot cơ bản có xử lý lỗi.
  • Biết cách chạy bot trên Testnet an toàn.

🧠 Bot giao dịch tự động là gì?​

Bot giao dịch tự động (trading bot) là một chương trình chạy liên tục, thực hiện 4 việc theo vòng lặp:

BướcCông việcCông cụ Python
1️⃣Thu thập dữ liệu — lấy giá, nến, khối lượngpython-binance, REST API
2️⃣Phân tích & ra quyết định — tính chỉ báo, xét điều kiệnpandas, numpy
3️⃣Quản lý rủi ro — tính khối lượng lệnh, stop-lossLogic Python thuần
4️⃣Thực thi — đặt/hủy lệnh qua APIpython-binance

Vòng lặp này lặp lại mỗi vài giây hoặc mỗi khi nến mới đóng. Đó chính là toàn bộ bản chất của một bot.

flowchart LR
A[Thu thập dữ liệu] --> B[Phân tích tín hiệu]
B --> C{Có tín hiệu?}
C -->|Không| A
C -->|Có| D[Tính khối lượng + rủi ro]
D --> E[Đặt lệnh qua API]
E --> F[Ghi log / thông báo]
F --> A

🧰 Cài đặt công cụ​

pip install python-binance pandas python-dotenv

Không bao giờ viết API key trực tiếp trong code. Hãy tạo file .env:

# .env  — KHÔNG commit file này lên Git
BINANCE_API_KEY=your_testnet_api_key
BINANCE_API_SECRET=your_testnet_api_secret
BINANCE_TESTNET=True

Và thêm .env vào .gitignore:

echo ".env" >> .gitignore

🔑 Bước 1: Tạo API Key trên Binance Testnet​

  1. Truy cập https://testnet.binance.vision/
  2. Đăng nhập bằng tài khoản GitHub.
  3. Bấm Generate HMAC_SHA256 Key.
  4. Sao chép API Key và Secret Key vào file .env.
  5. Testnet cho bạn sẵn số dư ảo (thường 10.000 USDT + một ít BTC/ETH) để thực hành.

🔌 Bước 2: Kết nối và kiểm tra tài khoản​

import os
from dotenv import load_dotenv
from binance.client import Client
from binance.exceptions import BinanceAPIException

load_dotenv()

API_KEY = os.getenv("BINANCE_API_KEY")
API_SECRET = os.getenv("BINANCE_API_SECRET")

# testnet=True -> chạy trên tiền ảo
client = Client(API_KEY, API_SECRET, testnet=True)

# 1. Kiểm tra kết nối
status = client.get_system_status()
print("Trạng thái hệ thống:", status)

# 2. Xem số dư
account = client.get_account()
for asset in account["balances"]:
free = float(asset["free"])
if free > 0:
print(f"{asset['asset']}: {free}")

Nếu thấy danh sách số dư in ra, bạn đã kết nối thành công. 🎉


📊 Bước 3: Lấy giá và tính chỉ báo đơn giản​

Bot cần biết giá hiện tại và tín hiệu. Ở đây ta dùng đường trung bình động (SMA) đơn giản — cầu nối từ các bài trước:

import pandas as pd

def get_klines(symbol="BTCUSDT", interval="1m", limit=100) -> pd.DataFrame:
"""Lấy nến và trả về DataFrame đã chuẩn hóa kiểu dữ liệu."""
klines = client.get_klines(symbol=symbol, interval=interval, limit=limit)
df = pd.DataFrame(klines, columns=[
"open_time", "open", "high", "low", "close", "volume",
"close_time", "quote_volume", "trades",
"taker_base", "taker_quote", "ignore",
])
for col in ["open", "high", "low", "close", "volume"]:
df[col] = df[col].astype(float)
df["open_time"] = pd.to_datetime(df["open_time"], unit="ms")
return df

def them_tin_hieu(df: pd.DataFrame, nhanh=9, cham=21) -> pd.DataFrame:
df["sma_nhanh"] = df["close"].rolling(nhanh).mean()
df["sma_cham"] = df["close"].rolling(cham).mean()
df["tin_hieu"] = 0
# Vàng cắt lên -> mua (1), cắt xuống -> bán (-1)
df.loc[df["sma_nhanh"] > df["sma_cham"], "tin_hieu"] = 1
df.loc[df["sma_nhanh"] < df["sma_cham"], "tin_hieu"] = -1
return df

df = them_tin_hieu(get_klines())
print(df[["open_time", "close", "sma_nhanh", "sma_cham", "tin_hieu"]].tail())

💡 Lưu ý về klines: Mỗi phần tử nến gồm 12 giá trị, trong đó giá và khối lượng là chuỗi — bạn luôn phải astype(float) trước khi tính toán, nếu không pandas sẽ cộng chuỗi và cho kết quả sai.


💰 Bước 4: Tính khối lượng lệnh đúng cách​

Sai lầm phổ biến nhất của người mới là đặt khối lượng tùy tiện. Hãy tính theo % rủi ro:

def tinh_khoi_luong(symbol, so_du_usdt, rui_ro_phan_tram=1.0, stop_loss_phan_tram=2.0):
"""Tính khối lượng (base asset) sao cho khi chạm stop-loss
chỉ mất đúng rui_ro_phan_tram % tổng số dư."""
gia = float(client.get_symbol_ticker(symbol=symbol)["price"])
so_tien_rui_ro = so_du_usdt * (rui_ro_phan_tram / 100)
khoang_cach_stop = gia * (stop_loss_phan_tram / 100)
khoi_luong = so_tien_rui_ro / khoang_cach_stop
return round(khoi_luong, 5), gia

khoi_luong, gia = tinh_khoi_luong("BTCUSDT", so_du_usdt=1000)
print(f"Giá BTC: {gia:,.2f} USDT | Khối lượng nên vào: {khoi_luong} BTC")

Công thức cốt lõi cần nhớ:

Khối lượng = (Số dư × % rủi ro) / (Giá × % stop-loss)

Ví dụ: số dư 1.000 USDT, rủi ro 1%, stop-loss 2%, giá BTC 60.000 USDT

Khối lượng = (1000 × 0.01) / (60000 × 0.02) = 10 / 1200 ≈ 0.00833 BTC

🚀 Bước 5: Đặt lệnh — Market và Limit​

from binance.enums import (
SIDE_BUY, SIDE_SELL,
ORDER_TYPE_MARKET, ORDER_TYPE_LIMIT,
TIME_IN_FORCE_GTC,
)

# --- Lệnh MARKET: khớp ngay lập tức theo giá thị trường ---
def mua_market(symbol, khoi_luong):
return client.create_order(
symbol=symbol,
side=SIDE_BUY,
type=ORDER_TYPE_MARKET,
quantity=khoi_luong,
)

# --- Lệnh LIMIT: chỉ khớp khi giá chạm mức bạn muốn ---
def mua_limit(symbol, khoi_luong, gia_mong_muon):
return client.create_order(
symbol=symbol,
side=SIDE_BUY,
type=ORDER_TYPE_LIMIT,
timeInForce=TIME_IN_FORCE_GTC,
quantity=khoi_luong,
price=str(gia_mong_muon),
)

if __name__ == "__main__":
ket_qua = mua_market("BTCUSDT", 0.001)
print("Đã đặt lệnh:", ket_qua["orderId"], ket_qua["status"])

Phân biệt nhanh:

Tiêu chíMarket OrderLimit Order
Khớp lệnhNgay lập tứcKhi giá chạm mức đặt
Kiểm soát giá❌ Không✅ Có
Rủi roTrượt giá (slippage)Lệnh không khớp
Phù hợpVào/thoát gấp, stop-lossVào giá đẹp, chốt lời

🛡️ Bước 6: Quản lý lệnh và vị thế​

def xem_lenh_dang_mo(symbol="BTCUSDT"):
lenh = client.get_open_orders(symbol=symbol)
return [
{
"id": l["orderId"],
"huong": l["side"],
"gia": float(l["price"]),
"kl": float(l["origQty"]),
"da_khop": float(l["executedQty"]),
}
for l in lenh
]

def huy_lenh(symbol, order_id):
return client.cancel_order(symbol=symbol, orderId=order_id)

for l in xem_lenh_dang_mo():
print(l)

🤖 Bước 7: Vòng lặp bot hoàn chỉnh​

Đây là phiên bản đầu tiên — đơn giản nhưng có đầy đủ xử lý lỗi, thứ mà 90% bot tự viết thiếu:

import time
import logging

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s | %(levelname)s | %(message)s",
handlers=[logging.FileHandler("bot.log", encoding="utf-8"), logging.StreamHandler()],
)

SYMBOL = "BTCUSDT"
vong_lap = 0
tin_hieu_truoc = 0

def lay_so_du_usdt():
for b in client.get_account()["balances"]:
if b["asset"] == "USDT":
return float(b["free"])
return 0.0

while True:
vong_lap += 1
try:
df = them_tin_hieu(get_klines(SYMBOL, "1m", 100))
tin_hieu_moi = int(df["tin_hieu"].iloc[-1])
gia = df["close"].iloc[-1]

logging.info(f"Vòng {vong_lap} | Giá {gia:,.2f} | Tín hiệu {tin_hieu_moi}")

# Chỉ hành động khi tín hiệu ĐỔI (tránh đặt lệnh liên tục)
if tin_hieu_moi != tin_hieu_truoc and tin_hieu_moi != 0:
if tin_hieu_moi == 1:
kl, _ = tinh_khoi_luong(SYMBOL, lay_so_du_usdt())
if kl > 0:
lenh = mua_market(SYMBOL, kl)
logging.info(f"✅ MUA {kl} {SYMBOL} (order {lenh['orderId']})")
else:
logging.info("📉 Tín hiệu bán — bỏ qua vì bot chưa hold vị thế")
tin_hieu_truoc = tin_hieu_moi

except BinanceAPIException as e:
logging.error(f"Lỗi API Binance: {e.message} (code {e.code})")
except Exception as e:
logging.exception(f"Lỗi không mong đợi: {e}")

time.sleep(60) # nghỉ 60 giây rồi lặp lại

Ba điểm sống còn trong đoạn code trên:

  1. try/except bao quanh toàn bộ thân vòng lặp — một lỗi mạng không được phép làm bot chết.
  2. time.sleep(60) — gọi API liên tục sẽ bị Binance chặn (rate limit) hoặc khóa key.
  3. Chỉ giao dịch khi tín hiệu đổi — nếu không, bot sẽ mua 60 lần mỗi giờ.

🧪 Bài tập thực hành​

  1. In ra 20 nến gần nhất cùng sma_nhanh, sma_cham dưới dạng bảng bằng pandas.
  2. Đổi interval sang "5m" và "1h", xem tín hiệu thay đổi thế nào.
  3. Viết hàm dat_stop_loss(symbol, gia_mua, phan_tram=2) đặt một STOP_MARKET order cách giá mua 2%.
  4. Ghi log số dư USDT sau mỗi 10 vòng lặp vào file so_du.csv.
  5. Thử phá bot: tắt mạng giữa chừng, xem bot có tự phục hồi không? Nếu chết, sửa lại.

⚠️ Lỗi thường gặp và cách xử lý​

LỗiNguyên nhânCách sửa
Invalid API-key, IP, or permissionsChưa bật quyền Spot Trading cho keyVào Testnet → API Management → bật Spot
MIN_NOTIONALGiá trị lệnh quá nhỏTăng khối lượng; kiểm tra client.get_symbol_info()
LOT_SIZEKhối lượng sai bước (step size)Làm tròn theo stepSize của symbol
Timestamp for this request is outside of the recvWindowĐồng hồ máy lệchBật đồng bộ giờ hệ thống
Bot "mua liên tục"Thiếu kiểm tra tín hiệu đổiLưu tin_hieu_truoc như ví dụ trên

📝 Ghi chú quan trọng​

  • Testnet ≠ Mainnet. Testnet có thanh khoản mỏng, giá đôi khi lệch; kết quả trên testnet không đảm bảo trên tiền thật.
  • Tuyệt đối không hard-code API key. Nếu vô tình push key lên GitHub, hãy thu hồi (revoke) ngay lập tức.
  • Không bật quyền Withdraw cho API key. Bot chỉ cần Spot Trading, không bao giờ cần rút tiền.
  • Log là bạn thân nhất của bạn. Bot chạy 24/7, bạn không thể ngồi nhìn — log là cách duy nhất biết nó đang làm gì.
  • Backtest trước, chạy thật sau. Một chiến lược chưa backtest thì chưa đáng để tin.

⚖️ Miễn trừ trách nhiệm: Nội dung này chỉ nhằm mục đích giáo dục về lập trình. Giao dịch tài sản số có rủi ro rất cao và có thể mất toàn bộ vốn. Hãy tự nghiên cứu và chỉ dùng tiền bạn có thể chấp nhận mất.


🎯 Tóm tắt ngày 44​

Bạn vừa xây xong bot giao dịch tự động đầu tiên:

✅ Kết nối Binance API an toàn qua .env ✅ Lấy nến, tính chỉ báo SMA bằng pandas ✅ Tính khối lượng theo % rủi ro ✅ Đặt lệnh market/limit, quản lý lệnh mở ✅ Vòng lặp bot có xử lý lỗi và ghi log


📚 Học tiếp​