Tác giả: Chuyên gia Quantitative Trading tại HolySheep AI

"Khi tôi lần đầu tiếp cận dữ liệu thanh lý futures, tôi đã mất 3 ngày chỉ để hiểu cấu trúc JSON trả về từ API. Sau 6 tháng thực chiến với mô hình risk management, tôi nhận ra rằng việc kết hợp Tardis Historical API + xử lý AI thực sự là combo mạnh mẽ nhất để xây dựng hệ thống cảnh báo rủi ro tự động."

Mục lục

1. Giới thiệu tổng quan

Dữ liệu thanh lý (liquidation data) là tín hiệu vàng trong giao dịch futures. Khi giá di chuyển đến mức liquidation price của một lệnh, vị thế sẽ bị đóng cưỡng bức — đây chính là lúc thị trường "bộc lộ cảm xúc thật" của traders.

Trong bài viết này, chúng ta sẽ học cách:

2. Tardis Historical API là gì

Tardis là dịch vụ cung cấp dữ liệu lịch sử chất lượng cao cho các sàn giao dịch tiền mã hóa, bao gồm Binance Futures. API của họ hỗ trợ:

Ưu điểm của Tardis so với API gốc của Binance

Tiêu chíBinance API gốcTardis API
Rate Limit1200 request/phútLin hoạt hơn
Cấu trúc dữ liệuPhức tạp, cần xử lý nhiềuĐã normalize, dễ xử lý
Historical dataGiới hạn 7 ngàyLên đến vài năm
Chi phíMiễn phí (có giới hạn)Freemium model

3. Cài đặt môi trường phát triển

3.1. Cài đặt Python và thư viện cần thiết

# Tạo virtual environment
python -m venv venv
source venv/bin/activate  # Linux/Mac

venv\Scripts\activate # Windows

Cài đặt các thư viện

pip install requests pandas numpy matplotlib pip install tardis-client python-dotenv pip install asyncio aiohttp # Cho async operations

3.2. Cấu trúc thư mục dự án

binance-risk-model/
├── config/
│   └── .env                 # API keys
├── data/
│   └── raw/                 # Dữ liệu thô
├── notebooks/               # Jupyter notebooks
├── src/
│   ├── __init__.py
│   ├── fetcher.py           # Lấy dữ liệu từ Tardis
│   ├── processor.py         # Xử lý dữ liệu
│   ├── analyzer.py          # Phân tích rủi ro
│   └── notifier.py          # Gửi cảnh báo
├── main.py                  # Entry point
└── requirements.txt

3.3. File cấu hình .env

# File: config/.env
TARDIS_API_KEY=your_tardis_api_key_here
TARDIS_API_SECRET=your_tardis_secret_here

HolySheep AI cho xử lý ngôn ngữ tự nhiên

HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1

4. Lấy dữ liệu thanh lý từ Binance qua Tardis API

4.1. Kết nối Tardis API

# File: src/fetcher.py
import os
import requests
from datetime import datetime, timedelta
from typing import List, Dict, Optional
from dotenv import load_dotenv

load_dotenv()

class TardisFetcher:
    """Lớp kết nối và lấy dữ liệu từ Tardis Historical API"""
    
    BASE_URL = "https://tardis.dev/api/v1"
    
    def __init__(self):
        self.api_key = os.getenv("TARDIS_API_KEY")
        if not self.api_key:
            raise ValueError("TARDIS_API_KEY không được tìm thấy trong .env")
    
    def get_liquidation_history(
        self, 
        symbol: str = "BTCUSDT",
        start_date: datetime = None,
        end_date: datetime = None,
        exchange: str = "binance-futures"
    ) -> List[Dict]:
        """
        Lấy lịch sử thanh lý cho một cặp tiền
        
        Args:
            symbol: Cặp giao dịch (VD: BTCUSDT, ETHUSDT)
            start_date: Ngày bắt đầu
            end_date: Ngày kết thúc
            exchange: Sàn giao dịch
        
        Returns:
            List chứa thông tin các lệnh thanh lý
        """
        if end_date is None:
            end_date = datetime.now()
        if start_date is None:
            start_date = end_date - timedelta(days=7)
        
        # Format thời gian theo ISO 8601
        start_str = start_date.isoformat()
        end_str = end_date.isoformat()
        
        url = f"{self.BASE_URL}/historical/liquidations/{exchange}:{symbol}"
        params = {
            "from": start_str,
            "to": end_str,
            "format": "json"
        }
        
        headers = {
            "Authorization": f"Bearer {self.api_key}"
        }
        
        response = requests.get(url, params=params, headers=headers)
        response.raise_for_status()
        
        return response.json()
    
    def get_liquidation_stream(self, symbols: List[str]):
        """
        Lấy real-time liquidation stream (WebSocket)
        """
        symbols_param = ",".join([f"{sym}" for sym in symbols])
        ws_url = f"wss://tardis.dev/api/v1/stream/live-logs/{symbols_param}"
        return ws_url

Sử dụng

if __name__ == "__main__": fetcher = TardisFetcher() # Lấy dữ liệu 7 ngày gần nhất liquidations = fetcher.get_liquidation_history( symbol="BTCUSDT", start_date=datetime.now() - timedelta(days=7) ) print(f"Tổng số liquidation: {len(liquidations)}") print(f"Mẫu dữ liệu đầu tiên: {liquidations[0] if liquidations else 'Không có dữ liệu'}")

4.2. Cấu trúc dữ liệu Liquidation

Mỗi record thanh lý từ Tardis có cấu trúc như sau:

{
    "symbol": "BTCUSDT",
    "side": "short",           # long hoặc short
    "price": 67234.50,         # Giá tại thời điểm thanh lý
    "size": 1.5,               # Số lượng hợp đồng
    "value": 100851.75,        # Giá trị USDT
    "timestamp": 1714300800000, # Unix timestamp (milliseconds)
    "order_type": "market",    # Loại lệnh gốc
    "leverage": 20,            # Đòn bẩy sử dụng
    "liquidation_price": 67000.00  # Giá thanh lý
}

4.3. Tải dữ liệu nhiều symbol cùng lúc

# File: src/batch_fetcher.py
import asyncio
import aiohttp
from datetime import datetime, timedelta
from src.fetcher import TardisFetcher
import pandas as pd

class BatchLiquidationFetcher:
    """Tải dữ liệu thanh lý cho nhiều cặp tiền song song"""
    
    def __init__(self):
        self.fetcher = TardisFetcher()
        self.symbols = [
            "BTCUSDT", "ETHUSDT", "BNBUSDT", 
            "SOLUSDT", "XRPUSDT", "ADAUSDT"
        ]
    
    async def fetch_symbol(self, session, symbol, days=7):
        """Lấy dữ liệu cho một symbol"""
        try:
            data = self.fetcher.get_liquidation_history(
                symbol=symbol,
                start_date=datetime.now() - timedelta(days=days)
            )
            return {
                "symbol": symbol,
                "data": data,
                "status": "success"
            }
        except Exception as e:
            return {
                "symbol": symbol,
                "data": [],
                "status": "error",
                "error": str(e)
            }
    
    async def fetch_all(self, days=7):
        """Lấy dữ liệu cho tất cả symbols"""
        async with aiohttp.ClientSession() as session:
            tasks = [
                self.fetch_symbol(session, sym, days) 
                for sym in self.symbols
            ]
            results = await asyncio.gather(*tasks)
            return results
    
    def to_dataframe(self, results):
        """Chuyển đổi kết quả thành DataFrame"""
        all_data = []
        for result in results:
            if result["status"] == "success":
                for item in result["data"]:
                    item["symbol"] = result["symbol"]
                    all_data.append(item)
        
        df = pd.DataFrame(all_data)
        if not df.empty:
            df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms")
        return df

Chạy

if __name__ == "__main__": fetcher = BatchLiquidationFetcher() print("Đang tải dữ liệu liquidation...") results = asyncio.run(fetcher.fetch_all(days=7)) df = fetcher.to_dataframe(results) print(f"\nTổng cộng {len(df)} records") print(df.head())

5. Xử lý và phân tích dữ liệu thanh lý

5.1. Làm sạch dữ liệu

# File: src/processor.py
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

class LiquidationProcessor:
    """Xử lý và làm sạch dữ liệu thanh lý"""
    
    def __init__(self, df: pd.DataFrame):
        self.df = df.copy()
    
    def clean_data(self):
        """Làm sạch dữ liệu"""
        # Loại bỏ duplicates
        self.df = self.df.drop_duplicates()
        
        # Xử lý missing values
        self.df = self.df.dropna(subset=["price", "size", "timestamp"])
        
        # Loại bỏ outliers (giá trị không hợp lệ)
        self.df = self.df[
            (self.df["size"] > 0) & 
            (self.df["price"] > 0) &
            (self.df["value"] > 0)
        ]
        
        # Chuẩn hóa timestamp
        self.df["timestamp"] = pd.to_datetime(self.df["timestamp"])
        
        return self
    
    def add_features(self):
        """Thêm các features cho phân tích"""
        # Thêm cột thời gian
        self.df["hour"] = self.df["timestamp"].dt.hour
        self.df["day_of_week"] = self.df["timestamp"].dt.dayofweek
        self.df["date"] = self.df["timestamp"].dt.date
        
        # Tính giá trị thanh lý theo USD
        self.df["liquidation_value_usd"] = self.df["size"] * self.df["price"]
        
        # Categorize liquidation size
        self.df["size_category"] = pd.cut(
            self.df["value"],
            bins=[0, 10000, 100000, 500000, float('inf')],
            labels=["Small", "Medium", "Large", "Whale"]
        )
        
        return self
    
    def aggregate_by_time(self, freq='1H'):
        """Tổng hợp theo khoảng thời gian"""
        self.df.set_index("timestamp", inplace=True)
        
        agg_df = self.df.groupby("symbol").resample(freq).agg({
            "value": ["sum", "count", "mean"],
            "size": "sum"
        }).reset_index()
        
        return agg_df
    
    def get_summary_stats(self):
        """Thống kê tổng quan"""
        summary = {
            "total_liquidations": len(self.df),
            "total_value": self.df["value"].sum(),
            "avg_value": self.df["value"].mean(),
            "median_value": self.df["value"].median(),
            "max_single_liquidation": self.df["value"].max(),
            "long_liquidations": len(self.df[self.df["side"] == "long"]),
            "short_liquidations": len(self.df[self.df["side"] == "short"]),
        }
        return summary

Sử dụng

if __name__ == "__main__": # Giả sử df là DataFrame đã load processor = LiquidationProcessor(df) processor.clean_data().add_features() summary = processor.get_summary_stats() print("=== Thống kê thanh lý ===") for key, value in summary.items(): print(f"{key}: {value:,.2f}" if isinstance(value, float) else f"{key}: {value}")

5.2. Phân tích theo khung giờ

# File: src/analyzer.py
import pandas as pd
import numpy as np

class LiquidationAnalyzer:
    """Phân tích sâu dữ liệu thanh lý"""
    
    def __init__(self, df: pd.DataFrame):
        self.df = df
    
    def analyze_by_hour(self):
        """Phân tích thanh lý theo giờ trong ngày"""
        hourly_stats = self.df.groupby("hour").agg({
            "value": ["sum", "count", "mean"],
            "symbol": "nunique"
        })
        return hourly_stats
    
    def analyze_by_side(self):
        """Phân tích theo side (long/short)"""
        side_stats = self.df.groupby("side").agg({
            "value": ["sum", "count", "mean", "max"],
            "price": "mean"
        })
        return side_stats
    
    def find_liquidation_clusters(self, price_col='price', window=50):
        """
        Tìm các cluster thanh lý (khu vực tập trung thanh lý)
        Quan trọng: Cluster thanh lý = vùng có thể gây cascade effect
        """
        # Sắp xếp theo giá
        sorted_df = self.df.sort_values(price_col).reset_index(drop=True)
        
        # Tính rolling sum của giá trị thanh lý
        sorted_df["value_cumsum"] = sorted_df["value"].cumsum()
        sorted_df["value_rolling"] = sorted_df["value"].rolling(window).sum()
        
        # Tìm local maxima - điểm có lượng thanh lý cao bất thường
        threshold = sorted_df["value_rolling"].mean() + 2 * sorted_df["value_rolling"].std()
        clusters = sorted_df[sorted_df["value_rolling"] > threshold]
        
        return clusters[["symbol", "price", "value", "size", "hour", "value_rolling"]]
    
    def calculate_liquidation_pressure(self, symbol):
        """
        Tính áp lực thanh lý cho một symbol
        - Long liquidation pressure: Giá có thể giảm do long squeeze
        - Short liquidation pressure: Giá có thể tăng do short squeeze
        """
        symbol_df = self.df[self.df["symbol"] == symbol]
        
        long_value = symbol_df[symbol_df["side"] == "long"]["value"].sum()
        short_value = symbol_df[symbol_df["side"] == "short"]["value"].sum()
        
        total = long_value + short_value
        if total == 0:
            return {"long_pressure": 0, "short_pressure": 0}
        
        return {
            "symbol": symbol,
            "long_pressure": round(long_value / total * 100, 2),
            "short_pressure": round(short_value / total * 100, 2),
            "dominant_side": "long" if long_value > short_value else "short",
            "pressure_ratio": round(max(long_value, short_value) / min(long_value, short_value), 2)
        }
    
    def detect_liquidation_spikes(self, threshold_std=3):
        """
        Phát hiện spike thanh lý - dấu hiệu thị trường cực đoan
        """
        hourly = self.df.groupby("hour")["value"].sum()
        mean_val = hourly.mean()
        std_val = hourly.std()
        
        spikes = hourly[hourly > mean_val + threshold_std * std_val]
        return spikes

Sử dụng

analyzer = LiquidationAnalyzer(df)

1. Phân tích theo giờ

print("=== Thanh lý theo giờ ===") print(analyzer.analyze_by_hour())

2. Tìm clusters

print("\n=== Liquidation Clusters ===") clusters = analyzer.find_liquidation_clusters() print(clusters.head(10))

3. Áp lực thanh lý

print("\n=== Áp lực thanh lý BTCUSDT ===") print(analyzer.calculate_liquidation_pressure("BTCUSDT"))

6. Xây dựng mô hình风控 (Risk Control Model)

6.1. Mô hình Liquidation Cascade Risk Score

Dưới đây là mô hình đơn giản nhưng hiệu quả để đánh giá rủi ro cascade thanh lý:

# File: src/risk_model.py
import pandas as pd
import numpy as np
from typing import Dict, List

class RiskModel:
    """
    Mô hình đánh giá rủi ro thanh lý
    Risk Score: 0-100 (càng cao = càng nguy hiểm)
    """
    
    def __init__(self, df: pd.DataFrame):
        self.df = df
    
    def calculate_risk_score(self, symbol: str = None) -> Dict:
        """
        Tính Risk Score dựa trên 5 yếu tố chính
        """
        if symbol:
            data = self.df[self.df["symbol"] == symbol]
        else:
            data = self.df
        
        if data.empty:
            return {"risk_score": 0, "risk_level": "UNKNOWN"}
        
        # Factor 1: Tổng giá trị thanh lý (quy mô)
        total_liquidation_value = data["value"].sum()
        liquidation_factor = min(100, total_liquidation_value / 1000000 * 30)
        
        # Factor 2: Tỷ lệ long/short không cân bằng
        long_val = data[data["side"] == "long"]["value"].sum()
        short_val = data[data["side"] == "short"]["value"].sum()
        total = long_val + short_val
        
        if total > 0:
            imbalance = abs(long_val - short_val) / total
            imbalance_factor = imbalance * 25
        else:
            imbalance_factor = 0
        
        # Factor 3: Concentration (thanh lý tập trung)
        top_10_pct = data["value"].nlargest(int(len(data) * 0.1)).sum()
        if total > 0:
            concentration = top_10_pct / total
            concentration_factor = concentration * 20
        else:
            concentration_factor = 0
        
        # Factor 4: Recent spike (thanh lý tăng đột biến gần đây)
        recent_24h = data[data["timestamp"] >= pd.Timestamp.now() - pd.Timedelta(hours=24)]
        historical_avg = data["value"].mean()
        recent_avg = recent_24h["value"].mean() if not recent_24h.empty else 0
        
        if historical_avg > 0:
            spike_ratio = recent_avg / historical_avg
            spike_factor = min(15, spike_ratio * 10)
        else:
            spike_factor = 0
        
        # Factor 5: Frequency (tần suất thanh lý)
        liquidation_count = len(data)
        frequency_factor = min(10, liquidation_count / 100)
        
        # Tổng hợp
        total_score = (
            liquidation_factor + 
            imbalance_factor + 
            concentration_factor + 
            spike_factor + 
            frequency_factor
        )
        
        # Xác định mức độ rủi ro
        if total_score >= 70:
            risk_level = "CRITICAL"
        elif total_score >= 50:
            risk_level = "HIGH"
        elif total_score >= 30:
            risk_level = "MEDIUM"
        else:
            risk_level = "LOW"
        
        return {
            "symbol": symbol or "ALL",
            "risk_score": round(total_score, 2),
            "risk_level": risk_level,
            "factors": {
                "liquidation_scale": round(liquidation_factor, 2),
                "imbalance": round(imbalance_factor, 2),
                "concentration": round(concentration_factor, 2),
                "recent_spike": round(spike_factor, 2),
                "frequency": round(frequency_factor, 2)
            },
            "recommendation": self._get_recommendation(risk_level)
        }
    
    def _get_recommendation(self, risk_level: str) -> str:
        """Đưa ra khuyến nghị dựa trên mức độ rủi ro"""
        recommendations = {
            "CRITICAL": "⚠️ KHÔNG mở vị thế mới. Cân nhắc đóng positions hiện tại. "
                       "Theo dõi sát vùng giá thanh lý lớn.",
            "HIGH": "⚡ Cẩn trọng với positions. Giảm đòn bẩy. "
                   "Chuẩn bị sẵn stop-loss.",
            "MEDIUM": "📊 Thị trường có biến động bất thường. "
                     "Quan sát và điều chỉnh position size.",
            "LOW": "✅ Thị trường ổn định. Có thể giao dịch với quản lý rủi ro thông thường."
        }
        return recommendations.get(risk_level, "")
    
    def generate_risk_report(self) -> pd.DataFrame:
        """Tạo báo cáo rủi ro cho tất cả symbols"""
        symbols = self.df["symbol"].unique()
        reports = []
        
        for symbol in symbols:
            risk_info = self.calculate_risk_score(symbol)
            reports.append({
                "Symbol": symbol,
                "Risk Score": risk_info["risk_score"],
                "Risk Level": risk_info["risk_level"],
                "Long Pressure %": risk_info["factors"]["imbalance"],
                "Recommendation": risk_info["recommendation"][:50] + "..."
            })
        
        return pd.DataFrame(reports).sort_values("Risk Score", ascending=False)

Chạy mô hình

risk_model = RiskModel(df) report = risk_model.generate_risk_report() print("=== BÁO CÁO RỦI RO ===") print(report.to_string())

Chi tiết cho BTC

btc_risk = risk_model.calculate_risk_score("BTCUSDT") print(f"\n=== Chi tiết BTCUSDT ===") print(f"Risk Score: {btc_risk['risk_score']}") print(f"Risk Level: {btc_risk['risk_level']}") print(f"Khuyến nghị: {btc_risk['recommendation']}")

7. Kết hợp HolySheep AI để phân tích và cảnh báo

Điểm mạnh của HolySheep AIđộ trễ thấp dưới 50mschi phí chỉ từ $0.42/MTok (DeepSeek V3.2), giúp bạn xử lý lượng lớn dữ liệu liquidation một cách hiệu quả về chi phí.

7.1. Gửi cảnh báo qua HolySheep AI

# File: src/notifier.py
import requests
import os
from datetime import datetime
from typing import Dict, List

class HolySheepNotifier:
    """Gửi thông báo và phân tích qua HolySheep AI API"""
    
    BASE_URL = "https://api.holysheep.ai/v1"
    
    def __init__(self):
        self.api_key = os.getenv("HOLYSHEEP_API_KEY")
        if not self.api_key:
            raise ValueError("HOLYSHEEP_API_KEY không được tìm thấy")
    
    def send_risk_alert(self, risk_data: Dict) -> Dict:
        """
        Gửi cảnh báo rủi ro qua AI, nhận phân tích chi tiết
        """
        prompt = f"""Bạn là chuyên gia phân tích rủi ro thị trường crypto.
        
Phân tích dữ liệu thanh lý sau và đưa ra khuyến nghị:

Symbol: {risk_data.get('symbol', 'N/A')}
Risk Score: {risk_data.get('risk_score', 0)}/100
Risk Level: {risk_data.get('risk_level', 'UNKNOWN')}
Chi tiết các yếu tố rủi ro:
- Liquidation Scale: {risk_data.get('factors', {}).get('liquidation_scale', 0)}
- Imbalance: {risk_data.get('factors', {}).get('imbalance', 0)}
- Concentration: {risk_data.get('factors', {}).get('concentration', 0)}
- Recent Spike: {risk_data.get('factors', {}).get('recent_spike', 0)}
- Frequency: {risk_data.get('factors', {}).get('frequency', 0)}

Hãy trả lời trong 200 từ, bao gồm:
1. Tóm tắt tình hình
2. 3 điểm cần theo dõi
3. Khuyến nghị hành động cụ thể"""

        response = requests.post(
            f"{self.BASE_URL}/chat/completions",
            headers={
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json"
            },
            json={
                "model": "deepseek-v3.2",  # Model rẻ nhất, phù hợp cho phân tích dữ liệu
                "messages": [
                    {"role": "user", "content": prompt}
                ],
                "max_tokens": 500,
                "temperature": 0.3  # Lower temperature cho phân tích chính xác
            }
        )
        
        response.raise_for_status()
        result = response.json()
        
        return {
            "status": "success",
            "analysis": result["choices"][0]["message"]["content"],
            "usage": result.get("usage", {}),
            "timestamp": datetime.now().isoformat()
        }
    
    def analyze_multiple_symbols(self, reports: List[Dict]) -> Dict:
        """
        Phân tích hàng loạt symbols, tìm cơ hội và rủi ro
        """
        # Tạo prompt tổng hợp
        symbols_summary = "\n".join([
            f"- {r['Symbol']}: Risk Score {r['Risk Score']} ({r['Risk Level']})"
            for r in reports
        ])
        
        prompt = f"""Phân tích toàn cảnh thị trường dựa trên dữ liệu thanh lý:

{symbols_summary}

Trả lời theo format:

Tổng quan

[Một đoạn về 2-3 câu]

Top 3 Rủi ro

1. [Symbol]: [Lý do] 2. ... 3. ...

Top 3 Cơ hội (nếu có)

1. [Symbol]: [Lý do] 2. ...

Chiến lược giao dịch tuần này

[3-4 câu recommendations] Giữ trong 300 từ.""" response = requests.post( f"{self.BASE_URL}/chat/completions", headers={ "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" }, json={ "model": "deepseek-v3.2", "messages": [{"role": "user", "content": prompt}], "max_tokens