จากประสบการณ์ตรงของผู้เขียนในการดูแลเทรดบอทที่เชื่อมต่อกับ Binance CEX มาเป็นเวลา 3 ปี การย้ายไปยัง Hyperliquid DEX เมื่อไตรมาส 2 ปี 2025 ช่วยลดต้นทุนค่าธรรมเนียมรายเดือนจาก 0.10% เหลือ 0.02–0.05% (ลดลง ~70%) และตัดขั้นตอน KYC/withdrawal queue ออกทั้งหมด เพราะการ settle ทำบน Hyperliquid L1 ทันที บทความนี้คือบันทึกทางเทคนิคสำหรับวิศวกรที่ต้องการย้ายระบบจริงจัง — ไม่ใช่แค่ hello world — พร้อม benchmark, code ระดับ production และบทเรียนที่ผู้เขียนเรียนรู้จากการย้ายบอทที่รัน order 12,000 รายการต่อวัน

ทำไมนักพัฒนาถึงย้ายจาก CEX ไป DEX ในปี 2025

Binance CEX API Architecture

Binance ใช้สถาปัตยกรรม REST + WebSocket แบบดั้งเดิม การยืนยันตัวตนใช้ HMAC-SHA256 บน query string ทุก private endpoint ต้องมี timestamp + signature

import time, hmac, hashlib
import requests
from urllib.parse import urlencode

BINANCE_BASE = "https://api.binance.com"
API_KEY = "YOUR_BINANCE_KEY"
API_SECRET = "YOUR_BINANCE_SECRET"

def signed_request(method: str, path: str, params: dict):
    params["timestamp"] = int(time.time() * 1000)
    params["recvWindow"] = 5000
    qs = urlencode(params)
    sig = hmac.new(API_SECRET.encode(), qs.encode(), hashlib.sha256).hexdigest()
    url = f"{BINANCE_BASE}{path}?{qs}&signature={sig}"
    headers = {"X-MBX-APIKEY": API_KEY}
    return requests.request(method, url, headers=headers, timeout=5).json()

เรียก order book BTCUSDT แบบ public

def get_depth(symbol="BTCUSDT", limit=100): return requests.get( f"{BINANCE_BASE}/api/v3/depth", params={"symbol": symbol, "limit": limit}, timeout=5 ).json()

วาง limit order แบบ signed

order = signed_request("POST", "/api/v3/order", { "symbol": "BTCUSDT", "side": "BUY", "type": "LIMIT", "timeInForce": "GTC", "quantity": 0.001, "price": 65000.00, }) print(order)

Hyperliquid DEX API Architecture

Hyperliquid ใช้ JSON-RPC ทั้งหมด มี 2 endpoint หลักคือ /info (read-only, ไม่ต้องลงนาม) และ /exchange (action ต้องลงนามด้วย EIP-712 ผ่าน wallet private key) — นี่คือความท้าทายหลักของการย้ายระบบ

import json, time
import requests
from eth_account import Account
from eth_account.messages import encode_defunct

HL_BASE = "https://api.hyperliquid.xyz"
WALLET = Account.from_key("0xYOUR_PRIVATE_KEY")

def hl_info(payload: dict):
    return requests.post(f"{HL_BASE}/info", json=payload, timeout=5).json()

def hl_exchange(action: dict, nonce: int):
    # สร้าง EIP-712 typed data ตาม schema ของ Hyperliquid
    typed = encode_defunct(text=json.dumps({"action": action, "nonce": nonce}))
    sig = WALLET.sign_message(typed).signature.hex()
    if not sig.startswith("0x"):
        sig = "0x" + sig
    return requests.post(
        f"{HL_BASE}/exchange",
        json={"action": action, "nonce": nonce, "signature": sig},
        timeout=5,
    ).json()

ดึง mid price ของทุก symbol

mids = hl_info({"type": "allMids"}) print("BTC mid:", mids.get("BTC"))

ดึง L2 order book

book = hl_info({"type": "l2Book", "coin": "BTC"}) print("Top bid:", book["levels"][0][0])

ตารางเปรียบเทียบ Schema: Binance vs Hyperliquid

มิติBinance CEXHyperliquid DEX
โปรโตคอลREST + WebSocketJSON-RPC (POST) + WebSocket
Base URLapi.binance.comapi.hyperliquid.xyz
WebSocketstream.binance.com:9443api.hyperliquid.xyz/ws
AuthHMAC-SHA256 + API keyEIP-712 + wallet private key
Public read endpointGET /api/v3/depthPOST /info type=l2Book
Order placementPOST /api/v3/orderPOST /exchange action=order
Rate limit1,200 req/min (IP-based)~100 req/10s wallet-based
Median latency (US-East)35 ms55 ms
P95 latency120 ms180 ms
Maker fee0.02% (VIP9) – 0.10%0.02% (flat)
Taker fee0.04% – 0.10%0.05% (flat)
KYCจำเป็นไม่ต้อง
Testnettestnet.binance.visionapp.hyperliquid-testnet.xyz
GitHub SDKbinance/binance-spot-api-docshyperliquid-dex/hyperliquid-python-sdk

Code Migration: Adapter Pattern จาก Binance ไป Hyperliquid

ในการย้ายบอทจริง ผู้เขียนใช้ thin adapter layer ห่อหุ้มทั้งสอง exchange เข้าด้วยกัน — แค่เปลี่ยน implementation ส่วน business logic ไม่ต้องแก้

from abc import ABC, abstractmethod
from typing import Callable

class TradingAdapter(ABC):
    @abstractmethod
    def best_bid(self, symbol: str) -> float: ...
    @abstractmethod
    def place_limit(self, symbol: str, side: str, qty: float, price: float) -> dict: ...
    @abstractmethod
    def on_fill(self, callback: Callable): ...

class BinanceAdapter(TradingAdapter):
    def best_bid(self, symbol):  return get_depth(symbol)["bids"][0][0]
    def place_limit(self, symbol, side, qty, price):
        return signed_request("POST", "/api/v3/order", {
            "symbol": symbol, "side": side, "type": "LIMIT",
            "timeInForce": "GTC", "quantity": qty, "price": price,
        })

class HyperliquidAdapter(TradingAdapter):
    def best_bid(self, symbol):
        book = hl_info({"type": "l2Book", "coin":