เคสเริ่มต้น: เมื่อบอท Arbitrage ของผมพลาดกำไร 12.4% ต่อเดือน
เรื่องนี้เกิดขึ้นเมื่อต้นปี 2026 ผมกำลังรันบอทเทรดข้ามกระดูกสำหรับสัญญา BTC Perpetual โดยอาศัยความแตกต่างของ Funding Rate ระหว่าง Binance, OKX และ Bybit ตอนแรกใช้แค่ WebSocket แบบ Real-time ผลปรากฏว่าในช่วงที่ตลาด sideways บอททำกำไรได้ประมาณ 4.1% ต่อเดือน แต่พอตลาดผันผวนหนัก บอทพลาดโอกาสไปเกือบ 12.4% ของ APR เพราะไม่มีข้อมูลย้อนหลังมากพอจะ backtest หาจังหวะ threshold ที่เหมาะสม และที่สำคัญคือข่าว macro ไม่ได้ถูกนำมาประกอบการตัดสินใจเลย ผมจึงตัดสินใจต่อยอดระบบด้วย Tardis.dev สำหรับข้อมูลย้อนหลัง และใช้ HolySheep AI เป็นโมดูลวิเคราะห์ข่าวเพราะ latency ต่ำกว่า 50 ms และราคาถูกกว่าการยิง OpenAI ตรงๆ ถึง 85%
พื้นฐาน Funding Rate ที่ต้องเข้าใจก่อนเขียนโค้ด
Funding Rate คือค่าธรรมเนียมที่ฝั่ง Long และ Short จ่ายให้กันเองทุก 8 ชั่วโมง (00:00, 08:00, 16:00 UTC) มีจุดประสงค์เพื่อให้ราคา Futures ไม่หลุดจาก Spot มากเกินไป ปกติค่าจะอยู่ที่ ±0.01% ต่อรอบ แต่ในช่วงที่ตลาดคาดว่าราคาจะขึ้น กระดูกหนึ่งอาจจ่าย 0.05% ขณะที่อีกกระดูกจ่าย 0.015% ตรงนี้แหละคือช่องว่างให้เรา short ฝั่งที่จ่ายสูง แล้ว long ฝั่งที่จ่ายต่ำ รอจน spread กลับมา converge ก็ปิด position
- รอบการจ่าย: ทุก 8 ชั่วโมง ค่า funding ใน 1 วันจึงมีผลกระทบสูงสุดประมาณ 3 เท่าของค่าต่อรอบ
- ความถี่ข้อมูล: Tardis เก็บ funding_rate ละเอียดระดับนาทีในสกุล derivative_ticker
- ค่าธรรมเนียม Maker/Taker: ต้องนำมาหักออกจาก spread ด้วย เพราะบางครั้ง spread ดูดีแต่ถ้าเปิด order แบบ Taker ทั้งสองข้าง กำไรอาจหายไปเกือบหมด
โครงสร้างระบบ Arbitrage ข้ามกระดูก
- Data Layer: ดึงข้อมูลย้อนหลังจาก Tardis เพื่อหา threshold ที่เหมาะสม
- Signal Layer: คำนวณ spread ระหว่างกระดูก + ใช้ LLM วิเคราะห์ข่าวเสริม
- Execution Layer: ส่งคำสั่งผ่าน API ของแต่ละกระดูก (Binance Futures, OKX V5, Bybit V5)
- Risk Layer: ตรวจ margin, slippage และ funding rate ที่อาจเปลี่ยนกะทันหัน
ขั้นตอนที่ 1: ดึงข้อมูลย้อนหลังจาก Tardis
# ติดตั้งก่อนใช้งาน: pip install tardis-dev pandas pyarrow requests
from tardis_dev import datasets
from datetime import datetime
import os
API_KEY = os.environ["TARDIS_API_KEY"] # สมัครฟรีที่ tardis.dev
exchanges = ["binance", "okx", "bybit"]
symbol = "btcusdt"
start = datetime(2024, 7, 1)
end = datetime(2025, 6, 30)
for ex in exchanges:
print(f"กำลังโหลดข้อมูล {ex} ...")
datasets.get(
exchange=ex,
symbols=symbol,
data_types="derivative_ticker",
from_date=start,
to_date=end,
download_dir="./tardis_data",
api_key=API_KEY,
)
print("ดาวน์โหลดเสร็จ ตรวจสอบโฟลเดอร์ tardis_data")
ขั้นตอนที่ 2: คำนวณ Spread และสร้างสัญญาณ
import pandas as pd
import numpy as np
def load(ex, base="./tardis_data"):
df = pd.read_parquet(f"{base}/{ex}/derivative_ticker/btcusdt/")
df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms", utc=True)
return df[["timestamp", "funding_rate", "mark_price"]].sort_values("timestamp")
binance = load("binance").rename(columns={"funding_rate": "fr_b"})
okx = load("okx").rename(columns={"funding_rate": "fr_o"})
bybit = load("bybit").rename(columns={"funding_rate": "fr_y"})
ใช้ merge_asof เพราะ timestamp ของแต่ละ exchange อาจคลาดกัน 1-3 วินาที
m = pd.merge_asof(binance, okx, on="timestamp",
direction="nearest", tolerance=pd.Timedelta("60s"))
m = pd.merge_asof(m, bybit, on="timestamp",
direction="nearest", tolerance=pd.Timedelta("60s"))
m["spread_OB"] = m["fr_o"] - m["fr_b"]
m["spread_YB"] = m["fr_y"] - m["fr_b"]
Threshold 0.03% ต่อรอบ (≈ 0.09% ต่อวัน) ถือว่าคุ้มค่าธรรมเนียม
TH = 0.0003
m["signal"] = np.select(
[m["spread_OB"] > TH, m["spread_YB"] > TH,
m["spread_OB"] < -TH, m["spread_YB"] < -TH],
["short_okx_long_binance", "short_bybit_long_binance",
"long_okx_short_binance", "long_bybit_short_binance"],
default="hold"
)
print(m["signal"].value