PKCryptolisting
WebSocket
Entegrasyon Kılavuzu
Sadece birkaç satır kodla Upbit, Bithumb, Binance ve Bybit'ten gerçek zamanlı duyurular alabilirsiniz.
Telegram bot'undan API anahtarınızı alın ve aşağıdaki kılavuzu izleyerek bağlanın.
ENDPOINT · KR
wss://kr.pkcryptolisting.com
Yalnızca Upbit · Bithumb
ENDPOINT · TOKYO
wss://tokyo.pkcryptolisting.com
Upbit · Bithumb · Binance · Bybit
PROTOCOL
WebSocket Secure (WSS)
AUTH
API Key (Telegram üzerinden alın)
SERVER LOCATION
AWS Seoul (ap-northeast-2) / AWS Tokyo (ap-northeast-1)
1. Bağlantı ve Kimlik Doğrulama
WebSocket bağlantısı kurulduktan hemen sonra bir kimlik doğrulama mesajı gönderilmelidir. 5 saniye içinde kimlik doğrulanmazsa otomatik olarak sonlandırılırbağlantı otomatik olarak sonlandırılır
Yalnızca belirli bir borsanın duyurularını almak için
Yalnızca belirli bir borsanın duyurularını almak için
exchange alanı ekleyin.
⚠️ Notlar
•
•
•
wss://kr.pkcryptolisting.com(Korea) uç noktası yalnızca
UPBIT ·
BITHUMB destekler.•
wss://tokyo.pkcryptolisting.com(Tokyo) uç noktası
UPBIT ·
BITHUMB ·
BINANCE ·
BYBIT dahil tüm borsaları destekler.
pip install websockets
npm install ws
go get github.com/gorilla/websocket
[dependencies]
tokio = { version = "1", features = ["full"] }
tokio-tungstenite = { version = "0.21", features = ["native-tls"] }
futures-util = "0.3"
serde_json = "1"
url = "2"import asyncio, json, websockets async def connect(): async with websockets.connect("wss://kr.pkcryptolisting.com") as ws: # or wss://tokyo.pkcryptolisting.com for all 4 exchanges # send auth message await ws.send(json.dumps({ "type": "auth", "key": "YOUR_API_KEY", # issued via Telegram bot # "exchange": "Upbit" # optional: "Upbit" | "Bithumb" (omit for all) })) asyncio.run(connect())
// npm install ws const WebSocket = require("ws"); const ws = new WebSocket("wss://kr.pkcryptolisting.com"); // or wss://tokyo.pkcryptolisting.com for all 4 exchanges ws.on("open", () => { // send auth message ws.send(JSON.stringify({ type: "auth", key: "YOUR_API_KEY", // issued via Telegram bot // exchange: "Upbit" // optional: "Upbit" | "Bithumb" (omit for all) })); });
// go get github.com/gorilla/websocket conn, _, _ := websocket.DefaultDialer.Dial("wss://kr.pkcryptolisting.com", nil)// or wss://tokyo.pkcryptolisting.com for all 4 exchanges // send auth message auth, _ := json.Marshal(map[string]string{"type": "auth", "key": "YOUR_API_KEY"}) // "exchange": "Upbit" // optional: "Upbit" | "Bithumb" (omit for all) conn.WriteMessage(websocket.TextMessage, auth)
let url = url::Url::parse("wss://kr.pkcryptolisting.com").unwrap();// or wss://tokyo.pkcryptolisting.com for all 4 exchanges let (mut ws, _) = connect_async(url).await.unwrap(); // send auth message let auth = serde_json::json!({"type": "auth", "key": "YOUR_API_KEY" // "exchange": "Upbit" // optional: "Upbit" | "Bithumb" (omit for all) }).to_string(); ws.send(Message::Text(auth)).await.ok();
2. Kimlik Doğrulama Yanıtı
Kimlik doğrulama başarılı olduğunda plan, gecikme ve son kullanma tarihi bilgileri döndürülür.
✓ Başarılı (auth_ok)
{ "type": "auth_ok", "plan": "premium", "delay_ms": 0, "expires_at": "2026-06-30", "message": "Connected..." }
✕ Başarısız (error)
{ "type": "error", "code": 4004, "message": "Invalid key" }
3. Mesaj Alımı
Kimlik doğrulama sonrası yeni bir duyuru algılandığında otomatik olarak alınır.
async for kullanıldığında, bağlantı sona erdiğinde döngüden otomatik olarak çıkılır.
# message loop — exits cleanly on disconnect async for raw in ws: msg = json.loads(raw) msg_type = msg.get("type") if msg_type == "auth_ok": print(f"connected plan={msg['plan']} delay={msg['delay_ms']}ms") elif msg_type == "error": print(f"error {msg['code']}: {msg['message']}") break elif msg_type == "plan_updated": # plan changed print(f"plan updated: {msg['plan']} delay={msg['delay_ms']}ms") else: # announcement print(f"[{msg['exchange']}] {msg['title']}") print(f" symbol={msg['symbol']} detected={msg['detectedTime']} {msg.get('timezone', '')}")
// message loop — exits cleanly on disconnect ws.on("message", (raw) => { const msg = JSON.parse(raw); if (msg.type === "auth_ok") console.log(`connected plan=${msg.plan} delay=${msg.delay_ms}ms`); else if (msg.type === "error") { console.log(`error ${msg.code}: ${msg.message}`); ws.close(); } else if (msg.type === "plan_updated") // plan changed console.log(`plan updated: ${msg.plan} delay=${msg.delay_ms}ms`); else { // announcement console.log(`[${msg.exchange}] ${msg.title}`); console.log(` symbol=${msg.symbol} detected=${msg.detectedTime} ${msg.timezone || ''}`); } });
// message loop — exits cleanly on disconnect for { _, raw, err := conn.ReadMessage() if err != nil { break } var msg map[string]interface{} json.Unmarshal(raw, &msg) switch msg["type"] { case "auth_ok": fmt.Printf("connected plan=%v delay=%vms ", msg["plan"], msg["delay_ms"]) case "error": fmt.Printf("error %v: %v ", msg["code"], msg["message"]); break case "plan_updated": // plan changed fmt.Printf("plan updated: %v delay=%vms ", msg["plan"], msg["delay_ms"]) default: // announcement fmt.Printf("[%v] %v ", msg["exchange"], msg["title"]) fmt.Printf(" symbol=%v detected=%v %v ", msg["symbol"], msg["detectedTime"], msg["timezone"]) } }
// message loop — exits cleanly on disconnect while let Some(Ok(raw)) = ws.next().await { let msg: Value = serde_json::from_str(&raw.to_string()).unwrap_or_default(); match msg["type"].as_str().unwrap_or("") { "auth_ok" => println!("connected plan={} delay={}ms", msg["plan"], msg["delay_ms"]), "error" => { println!("error {}: {}", msg["code"], msg["message"]); break; } "plan_updated" => // plan changed println!("plan updated: {} delay={}ms", msg["plan"], msg["delay_ms"]), _ => { // announcement println!("[{}] {}", msg["exchange"], msg["title"]); println!(" symbol={} detected={} {}", msg["symbol"], msg["detectedTime"], msg["timezone"]); } } }
4. Alınan Veri Formatı
Duyuru verisi aşağıdaki formatta iletilir.
symbol alanı tek bir dize, bir dizi (array) veya boş bir dize olabilir.
⚠️ Notlar
•
•
•
title, category
Alanlar, UPBIT · BITHUMB için Korece, BINANCE · BYBIT için orijinal İngilizce olarak alınır.•
detectedTime —
Motorumuzun duyuruyu algıladığı zaman (mikrosaniye hassasiyeti)
{ "title": "펏지펭귄(PENGU) 신규 거래지원 안내 (KRW, BTC, USDT 마켓)", "category": "거래", "symbol": "PENGU", "exchange": "Upbit", "detectedTime": "2025-05-09 15:00:00.333851", "timezone": "KST", "url": "https://www.upbit.com/service_center/notice?id=5104&view=share" }
| Alan | Tür | Açıklama |
|---|---|---|
| title | string | Borsa duyurusunun orijinal başlığı |
| category | string | Duyuru kategorisi — aşağıdaki kategori listesine bakın |
| symbol | string | array |
Çıkarılan coin sembolü. Tekil: "BTC", Çoklu: ["BTC","ETH"], Boşsa: "", Free plan: "***"
|
| exchange | string |
Duyuru kaynağı borsa: "Upbit", "Bithumb", "Binance", "Bybit"
|
| detectedTime | string | Motorumuzun duyuruyu algıladığı zaman (mikrosaniye hassasiyeti). Basic planda +30ms ek gecikme uygulanır |
| timezone | string | detectedTime için referans zaman dilimi. KST (Upbit, Bithumb) veya UTC (Binance, Bybit) |
| url | string | Orijinal duyuru bağlantısı |
Plan Farkları
Tüm planlar aynı altyapıyı kullanır. Yalnızca gecikme ve sembol görünürlüğü farklıdır.
Free
0ms Gecikme
Sembol *** Maskeleme
Basic
+30ms Gecikme
Tam Sembol Görünürlüğü
Premium
0ms Gecikme
Tam Sembol Görünürlüğü
⚠️ Notlar
• Tek bir API Key ile tek bir bölgeden birden fazla cihaz bağlantısına izin verilmez şeklinde Zaten aktif bir bağlantı varken başka bir yerden bağlanmaya çalışılırsa, yeni bağlantı denemesi hata kodu
• Tek bir API Key ile tek bir bölgeden birden fazla cihaz bağlantısına izin verilmez şeklinde Zaten aktif bir bağlantı varken başka bir yerden bağlanmaya çalışılırsa, yeni bağlantı denemesi hata kodu
4006 ile engellenir.
Hata Kodları
Bağlantı veya kimlik doğrulama başarısız olduğunda aşağıdaki kodlar döndürülür.
| CODE | Açıklama | Çözüm |
|---|---|---|
| 4001 | Kimlik Doğrulama Zaman Aşımı | Bağlandıktan sonra 5 saniye içinde bir auth mesajı gönderin. |
| 4002 | Geçersiz JSON | JSON formatını doğrulayın. |
| 4003 | Eksik Kimlik Doğrulama Mesajı | type: "auth" mesajı gereklidir. |
| 4004 | Geçersiz Anahtar | Anahtarınızı Telegram bot'undan kontrol edin. |
| 4005 | Abonelik Süresi Doldu | Planınızı Telegram bot'u üzerinden yenileyin. |
| 4006 | Yinelenen Bağlantı | Mevcut bağlantıyı sonlandırın ve yeniden bağlanın. |
| 4029 | Çok Fazla İstek (Hız Sınırı) | Lütfen daha sonra tekrar deneyin |
Kategoriler
Bu, alınan değerlerin bir listesidir.
category alan değerleri UPBIT · BITHUMB için Korece, BINANCE · BYBIT için orijinal İngilizce olarak alınır.
Tam Örnek Kod
Otomatik yeniden bağlanma ve üstel geri çekilme (exponential backoff) uygulanmış eksiksiz çalışan bir koddur. Sadece
YOUR_API_KEY
değiştirip hemen çalıştırın.
import asyncio, json, websockets KEY = "YOUR_API_KEY" # issued via Telegram bot ENDPOINT = "wss://kr.pkcryptolisting.com" RETRIES = 20 def handle_notice(evt: dict): exchange = evt.get("exchange", "") title = evt.get("title", "") category = evt.get("category", "") symbol = evt.get("symbol", "") detected = evt.get("detectedTime", "") timezone = evt.get("timezone", "") url = evt.get("url", "") print(f"[{exchange}] [{category}] {title}") print(f" symbol={symbol}") print(f" detected={detected} {timezone}") print(f" {url}") async def listen(): for attempt in range(RETRIES): try: async with websockets.connect(ENDPOINT) as ws: await ws.send(json.dumps({"type": "auth", "key": KEY})) async for raw in ws: evt = json.loads(raw) evt_type = evt.get("type") if evt_type == "auth_ok": print(f"connected plan={evt['plan']} delay={evt['delay_ms']}ms expires={evt['expires_at']}") attempt = 0 # reset retry counter on success elif evt_type == "error": print(f"[{evt['code']}] {evt['message']}") if evt["code"] in (4004, 4005, 4006, 4029): return # do not reconnect break elif evt_type == "plan_updated": print(f"plan changed → {evt['plan']} delay={evt['delay_ms']}ms expires={evt['expires_at']}") else: handle_notice(evt) except websockets.ConnectionClosed as e: print(f"closed: {e}") except Exception as e: print(f"error: {e}") backoff = min(2 ** attempt, 300) print(f"retry in {backoff}s...") await asyncio.sleep(backoff) if __name__ == "__main__": asyncio.run(listen())
// npm install ws const WebSocket = require("ws"); const KEY = "YOUR_API_KEY"; // issued via Telegram bot const ENDPOINT = "wss://kr.pkcryptolisting.com"; const RETRIES = 20; function handleNotice(evt) { console.log(`[${evt.exchange}] [${evt.category}] ${evt.title}`); console.log(` symbol=${evt.symbol}`); console.log(` detected=${evt.detectedTime} ${evt.timezone || ''}`); console.log(` ${evt.url}`); } function listen(attempt = 0) { if (attempt >= RETRIES) return; const ws = new WebSocket(ENDPOINT); ws.on("open", () => ws.send(JSON.stringify({ type: "auth", key: KEY }))); ws.on("message", (raw) => { const evt = JSON.parse(raw); if (evt.type === "auth_ok") { console.log(`connected plan=${evt.plan} delay=${evt.delay_ms}ms expires=${evt.expires_at}`); attempt = 0; // reset retry counter on success } else if (evt.type === "error") { console.log(`[${evt.code}] ${evt.message}`); if ([4004,4005,4006,4029].includes(evt.code)) return; // do not reconnect ws.close(); } else if (evt.type === "plan_updated") console.log(`plan changed → ${evt.plan} delay=${evt.delay_ms}ms expires=${evt.expires_at}`); else handleNotice(evt); }); ws.on("close", () => { const b = Math.min(2 ** attempt, 300); console.log(`retry in ${b}s...`); setTimeout(() => listen(attempt + 1), b * 1000); }); ws.on("error", (e) => console.log(`error: ${e.message}`)); } listen();
// go get github.com/gorilla/websocket package main import ( "encoding/json"; "fmt"; "math"; "time" "github.com/gorilla/websocket" ) const (key = "YOUR_API_KEY"; endpoint = "wss://kr.pkcryptolisting.com"; retries = 20) // issued via Telegram bot type Evt struct { Type,Plan,Message,ExpiresAt,Exchange,Title,Category,DetectedTime,Timezone,URL string Code,DelayMs int; Symbol interface{} } func handleNotice(e Evt) { fmt.Printf("[%s] [%s] %s symbol=%v detected=%s %s ", e.Exchange, e.Category, e.Title, e.Symbol, e.DetectedTime, e.Timezone, e.URL) } func listen() { for a := 0; a < retries; a++ { c, _, err := websocket.DefaultDialer.Dial(endpoint, nil) if err != nil { fmt.Println("error:", err) } else { b, _ := json.Marshal(map[string]string{"type":"auth","key":key}) c.WriteMessage(websocket.TextMessage, b) for { _, raw, err := c.ReadMessage(); if err != nil { fmt.Println("closed:", err); break } var e Evt; json.Unmarshal(raw, &e) switch e.Type { case "auth_ok": fmt.Printf("connected plan=%s delay=%dms expires=%s ",e.Plan,e.DelayMs,e.ExpiresAt); a=0 // reset retry counter on success case "error": fmt.Printf("[%d] %s ",e.Code,e.Message) if e.Code==4004||e.Code==4005||e.Code==4006||e.Code==4029 { return } // do not reconnect case "plan_updated": fmt.Printf("plan changed → %s delay=%dms expires=%s ",e.Plan,e.DelayMs,e.ExpiresAt) default: handleNotice(e) } }; c.Close() } bf := time.Duration(math.Min(math.Pow(2,float64(a)),300))*time.Second fmt.Printf("retry in %vs... ", bf.Seconds()); time.Sleep(bf) } } func main() { listen() }
use futures_util::{SinkExt, StreamExt}; use tokio_tungstenite::{connect_async, tungstenite::Message}; use serde_json::{json, Value}; use std::time::Duration; const KEY: &str = "YOUR_API_KEY"; // issued via Telegram bot const ENDPOINT: &str = "wss://kr.pkcryptolisting.com"; const RETRIES: u32 = 20; fn handle_notice(e: &Value) { println!("[{}] [{}] {} symbol={} detected={} {} {}", e["exchange"],e["category"],e["title"],e["symbol"],e["detectedTime"],e["timezone"],e["url"]); } #[tokio::main] async fn main() { for attempt in 0..RETRIES { match connect_async(url::Url::parse(ENDPOINT).unwrap()).await { Ok((mut ws, _)) => { ws.send(Message::Text(json!({"type":"auth","key":KEY}).to_string())).await.ok(); while let Some(Ok(raw)) = ws.next().await { if let Ok(e) = serde_json::from_str::<Value>(&raw.to_string()) { match e["type"].as_str().unwrap_or("") { "auth_ok" => println!("connected plan={} delay={}ms expires={}", e["plan"],e["delay_ms"],e["expires_at"]), "error" => { println!("[{}] {}",e["code"],e["message"]); let c=e["code"].as_i64().unwrap_or(0); if [4004,4005,4006,4029].contains(&c) { return; } // do not reconnect break; } "plan_updated" => println!("plan changed → {} delay={}ms expires={}", e["plan"],e["delay_ms"],e["expires_at"]), _ => handle_notice(&e), } } } } Err(e) => println!("error: {}", e), } let b = (2u64.pow(attempt)).min(300); println!("retry in {}s...", b); tokio::time::sleep(Duration::from_secs(b)).await; } }
API Anahtarı Al
Telegram bot'undan ücretsiz olarak alabilirsiniz.
Ücretli plana yükseltme işlemi de bot üzerinden yapılabilir.