כצוות של מהנדסי בלוקצ'יין, אנו מקבלים לעיתים קרובות בקשות לשלב בוטים למסחר עם KuCoin. במבט ראשון, ה-API נראה סטנדרטי—REST ו-WebSocket. אבל בפועל, מפתחים נתקלים באימות v2 (passphrase בקידוד base64), כתובת WebSocket דינמית, ומגבלות קצב. פעם אחת, לקוח הפסיד 2 ETH בגלל חותמת זמן שגויה—ההזמנות התעכבו ונכנסו לאזור המיושן. בואו נפרק כיצד לבנות בוט עמיד לתקלות שחוסך כסף ועצבים. מעבר מהזמנות שוק להזמנות limit יכול לחסוך עד 30% בעמלות—במקרה אחד, מעל 300 דולר בחודש. ומנוי נכון ל-WebSocket מפחית את זמן ההשהיה ב-80%, ובעקיפין חוסך עוד 0.5% בהחלקת מחיר (slippage).
כיצד פועל האימות של KuCoin ולמה הוא לא סטנדרטי
KuCoin משתמש בחתימות HMAC-SHA256. נקודה חשובה: ה-passphrase גם הוא נחתם ומקודד ב-base64. להלן מחלקה עובדת ליצירת כותרות.
import hmac
import hashlib
import base64
import time
import json
import httpx
class KuCoinClient:
BASE_URL = "https://api.kucoin.com"
FUTURES_URL = "https://api-futures.kucoin.com"
def __init__(self, api_key: str, api_secret: str, passphrase: str):
self.api_key = api_key
self.api_secret = api_secret
# KuCoin v2 подпись: passphrase тоже подписывается
self.passphrase = base64.b64encode(
hmac.new(api_secret.encode(), passphrase.encode(), hashlib.sha256).digest()
).decode()
def _sign(self, timestamp: str, method: str, endpoint: str, body: str = "") -> str:
str_to_sign = timestamp + method.upper() + endpoint + body
return base64.b64encode(
hmac.new(self.api_secret.encode(), str_to_sign.encode(), hashlib.sha256).digest()
).decode()
def _headers(self, method: str, endpoint: str, body: str = "") -> dict:
timestamp = str(int(time.time() * 1000))
return {
"KC-API-KEY": self.api_key,
"KC-API-SIGN": self._sign(timestamp, method, endpoint, body),
"KC-API-TIMESTAMP": timestamp,
"KC-API-PASSPHRASE": self.passphrase,
"KC-API-KEY-VERSION": "2",
"Content-Type": "application/json"
}לפי תיעוד KuCoin, חותמת הזמן חייבת להיות שונה מזו של השרת בלא יותר מ-5 שניות—אחרת import hmac import hashlib import base64 import time import json import httpx class KuCoinClient: BASE_URL = "https://api.kucoin.com" FUTURES_URL = "https://api-futures.kucoin.com" def __init__(self, api_key: str, api_secret: str, passphrase: str): self.api_key = api_key self.api_secret = api_secret # KuCoin v2 подпись: passphrase тоже подписывается self.passphrase = base64.b64encode( hmac.new(api_secret.encode(), passphrase.encode(), hashlib.sha256).digest() ).decode() def _sign(self, timestamp: str, method: str, endpoint: str, body: str = "") -> str: str_to_sign = timestamp + method.upper() + endpoint + body return base64.b64encode( hmac.new(self.api_secret.encode(), str_to_sign.encode(), hashlib.sha256).digest() ).decode() def _headers(self, method: str, endpoint: str, body: str = "") -> dict: timestamp = str(int(time.time() * 1000)) return { "KC-API-KEY": self.api_key, "KC-API-SIGN": self._sign(timestamp, method, endpoint, body), "KC-API-TIMESTAMP": timestamp, "KC-API-PASSPHRASE": self.passphrase, "KC-API-KEY-VERSION": "2", "Content-Type": "application/json" } . בפרויקטים שלנו, אנו מסנכרנים שעונים באמצעות NTP וקוראים את זמן השרת מכותרת התגובה 401000 בכל בקשה.
מדריך שלב-אחר-שלב ליצירת מפתח API
- היכנס לחשבון KuCoin שלך, עבור אל
KC-API-TIMESTAMP→Настройки. - לחץ על Create API Key.
- בחר גרסה 2.
- הגדר passphrase (לפחות 8 תווים).
- שמור את מפתח ה-API, הסוד וה-passphrase—הם מוצגים רק פעם אחת.
- השתמש במחלקה שלמעלה בקוד שלך, תוך העברת המפתחות.
מה יותר מהיר: REST או WebSocket?
| קריטריון | REST API | WebSocket API |
|---|---|---|
| זמן השהיית מחיר | 200–500 אלפיות השנייה (סקרים) | 10–50 אלפיות השנייה (push) |
| עומס על השרת | גבוה (סקרים) | נמוך (מנוי) |
| חיבורים נדרשים | HTTP חד-פעמי | WS קבוע |
| מגבלות קצב | 30 בקשות/שנייה | 100 חיבורים לחשבון |
לאסטרטגיות בתדירות גבוהה, WebSocket מהיר פי 5–10 מ-REST. עם זאת, יציבות חיבור WebSocket דורשת הטמעת לוגיקת התחברות מחדש ו-keepalive.
כיצד להציב הזמנות דרך REST
async def place_order(
self,
symbol: str, # 'BTC-USDT'
side: str, # 'buy' или 'sell'
order_type: str, # 'limit' или 'market'
size: str = None,
price: str = None,
funds: str = None # для market buy по котируемой
) -> dict:
endpoint = "/api/v1/orders"
payload = {
"clientOid": str(int(time.time() * 1000)), # уникальный ID клиента
"symbol": symbol,
"side": side,
"type": order_type
}
if order_type == "limit":
payload["size"] = size
payload["price"] = price
elif side == "buy" and funds:
payload["funds"] = funds # купить на $X USDT
else:
payload["size"] = size
body = json.dumps(payload)
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.BASE_URL}{endpoint}",
content=body,
headers=self._headers("POST", endpoint, body)
)
result = response.json()
if result.get("code") != "200000":
raise KuCoinError(f"Order error: {result.get('msg')}")
return result["data"]
async def get_accounts(self, currency: str = None) -> list:
endpoint = "/api/v1/accounts"
if currency:
endpoint += f"?currency={currency}"
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.BASE_URL}{endpoint}",
headers=self._headers("GET", endpoint)
)
return response.json().get("data", [])שים לב: API חייב להיות ייחודי לכל הזמנה. אנו מייצרים אותו על בסיס חותמת זמן ומחרוזת אקראית כדי למנוע התנגשויות בעת שליחה חוזרת. זה קריטי לאסטרטגיות שבהן אנו מחליפים הזמנות כשהמחיר משתנה.
למה WebSocket דורש כתובת URL דינמית?
KuCoin לא מפרסם כתובת WebSocket סטטית—יש לבקש אותה. זה משפר את האבטחה: הטוקן פג לאחר 24 שעות. הלקוח שלנו מביא את נקודת הקצה, מתחבר ושומר על keepalive.
async def get_ws_endpoint(self, private: bool = False) -> dict:
endpoint = "/api/v1/bullet-private" if private else "/api/v1/bullet-public"
method = "POST" if private else "POST"
headers = self._headers(method, endpoint) if private else {"Content-Type": "application/json"}
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.BASE_URL}{endpoint}",
headers=headers
)
data = response.json()["data"]
server = data["instanceServers"][0]
token = data["token"]
ws_url = f"{server['endpoint']}?token={token}&connectId={int(time.time()*1000)}"
ping_interval = server["pingInterval"] / 1000 # в секундах
return {"url": ws_url, "ping_interval": ping_interval}
async def subscribe_ticker(self, symbols: list[str]):
ws_data = await self.get_ws_endpoint(private=False)
async with websockets.connect(ws_data["url"]) as ws:
await ws.send(json.dumps({
"id": str(int(time.time() * 1000)),
"type": "subscribe",
"topic": f"/market/ticker:{','.join(symbols)}",
"privateChannel": False,
"response": True
}))
async def keepalive():
while True:
await asyncio.sleep(ws_data["ping_interval"])
await ws.send(json.dumps({"id": "ping", "type": "ping"}))
asyncio.create_task(keepalive())
async for message in ws:
data = json.loads(message)
if data["type"] == "message" and "data" in data:
await self.on_ticker(data["data"])
בעיה אופיינית ב-WebSocket: ניתוק חיבור ללא הודעה. במהלך חוסר פעילות ממושך, KuCoin עלול לסגור את ה-socket מבלי לשלוח פריים סגירה. מטפל השגיאות שלנו מתחבר מחדש אוטומטית עם backoff אקספוננציאלי (1 שנייה, 2 שניות, 4 שניות... עד 30 שניות). זה מכסה 99.9% מהמקרים.
אילו שגיאות הן הנפוצות ביותר?
| שגיאה | סיבה | פתרון |
|---|---|---|
async def place_order( self, symbol: str, # 'BTC-USDT' side: str, # 'buy' или 'sell' order_type: str, # 'limit' или 'market' size: str = None, price: str = None, funds: str = None # для market buy по котируемой ) -> dict: endpoint = "/api/v1/orders" payload = { "clientOid": str(int(time.time() * 1000)), # уникальный ID клиента "symbol": symbol, "side": side, "type": order_type } if order_type == "limit": payload["size"] = size payload["price"] = price elif side == "buy" and funds: payload["funds"] = funds # купить на $X USDT else: payload["size"] = size body = json.dumps(payload) async with httpx.AsyncClient() as client: response = await client.post( f"{self.BASE_URL}{endpoint}", content=body, headers=self._headers("POST", endpoint, body) ) result = response.json() if result.get("code") != "200000": raise KuCoinError(f"Order error: {result.get('msg')}") return result["data"] async def get_accounts(self, currency: str = None) -> list: endpoint = "/api/v1/accounts" if currency: endpoint += f"?currency={currency}" async with httpx.AsyncClient() as client: response = await client.get( f"{self.BASE_URL}{endpoint}", headers=self._headers("GET", endpoint) ) return response.json().get("data", []) |
חתימה לא חוקית | בדוק את אלגוריתם HMAC, ה-passphrase, חותמת הזמן |
clientOid |
חותמת זמן פגה | ההפרש מהשרת חייב להיות ≤5 שניות |
async def get_ws_endpoint(self, private: bool = False) -> dict: endpoint = "/api/v1/bullet-private" if private else "/api/v1/bullet-public" method = "POST" if private else "POST" headers = self._headers(method, endpoint) if private else {"Content-Type": "application/json"} async with httpx.AsyncClient() as client: response = await client.post( f"{self.BASE_URL}{endpoint}", headers=headers ) data = response.json()["data"] server = data["instanceServers"][0] token = data["token"] ws_url = f"{server['endpoint']}?token={token}&connectId={int(time.time()*1000)}" ping_interval = server["pingInterval"] / 1000 # в секундах return {"url": ws_url, "ping_interval": ping_interval} async def subscribe_ticker(self, symbols: list[str]): ws_data = await self.get_ws_endpoint(private=False) async with websockets.connect(ws_data["url"]) as ws: await ws.send(json.dumps({ "id": str(int(time.time() * 1000)), "type": "subscribe", "topic": f"/market/ticker:{','.join(symbols)}", "privateChannel": False, "response": True })) async def keepalive(): while True: await asyncio.sleep(ws_data["ping_interval"]) await ws.send(json.dumps({"id": "ping", "type": "ping"})) asyncio.create_task(keepalive()) async for message in ws: data = json.loads(message) if data["type"] == "message" and "data" in data: await self.on_ticker(data["data"]) |
חריגה ממגבלת קצב | הכנס השהיות, השתמש בכותרות מגבלת קצב |
ה-API של KuCoin מחזיר code: "400003" על הצלחה (לא סטטוס HTTP). בדוק תמיד את השדה הזה.
המאפיינים של KuCoin Futures API
KuCoin מספק דומיין נפרד ל-API של החוזים העתידיים: code: "401000". האימות זהה לגרסת הספוט, אבל נקודות הקצה שונות. למסחר אלגוריתמי, הבוט הקריפטו שלנו משתמש בסוגי הזמנות מתקדמים. הגדרה נכונה של code: "429000" ו-code: "200000" (מבודד או צולב) היא קריטית. שער המימון מתעדכן כל 8 שעות—זמין דרך https://api-futures.kucoin.com. ניטור שער המימון עוזר להימנע מחיובים לא רצויים כשמחזיקים פוזיציה דרך תקופת הסילוק.
מה כלול בפתרון מפתח
- עיצוב ארכיטקטורת בוט (אסטרטגיה, ניהול סיכונים, בחירת ספוט/חוזים עתידיים)
- הטמעת לקוח עם טיפול במגבלות קצב, התחברויות מחדש ורישום שגיאות מלא
- בדיקות בסביבת ה-sandbox (כיסוי מלא של תרחישים: הזמנות, ביטולים, מילוי חלקי)
- פריסה על השרת שלך או בענן (Docker, systemd, ניטור דרך Grafana)
- תיעוד API ותפעול: איך להפעיל מחדש, איך לשנות אסטרטגיות
- תמיכה של 30 יום לאחר ההשקה: תיקוני באגים, ייעוץ
אנו מבטיחים יציבות: לצוות שלנו יש ניסיון של 7+ שנים במסחר קריפטו. כדי להשיק בוט בסביבת ייצור, צור איתנו קשר—נכין את הארכיטקטורה תוך יומיים ונעזור לך להימנע מטעויות אינטגרציה נפוצות. קבל ייעוץ לפרויקט שלך—נדון באסטרטגיה, סיכונים ופרטים טכניים.







