บทความนี้อธิบายวิธีสร้าง Deribit Greeks ข้อมูลประวัติ (Historical Data Operations Dashboard) ที่ครอบคลุม 4 มิติสำคัญ ได้แก่ Data Completeness Rate, Recalculation Tasks, Strategy Dependencies และ Research Team Satisfaction โดยใช้สถาปัตยกรรม Production-Grade ที่รองรับ High-Throughput และ Low-Latency

ภาพรวมสถาปัตยกรรมระบบ

ระบบนี้ออกแบบมาเพื่อรองรับการประมวลผล Greeks Data จาก Deribit Exchange โดยมีส่วนประกอบหลักดังนี้:

การดึงข้อมูล Greeks จาก Deribit

Deribit API ให้ข้อมูล Greeks ผ่าน public/get_book_summary_by_instrument และ GET /api/v2/public/get_greeks โดยมี Rate Limit ที่ 10 requests/second สำหรับ Public API

สคริปต์ดึงข้อมูล Greeks พร้อม Data Quality Check

#!/usr/bin/env python3
"""
Deribit Greeks Historical Data Fetcher
Production-Grade Implementation พร้อม Retry Logic และ Data Validation
"""
import asyncio
import aiohttp
import hashlib
import logging
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from typing import Optional, Dict, List
from tenacity import retry, stop_after_attempt, wait_exponential
import timescaledb

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@dataclass
class GreeksRecord:
    """โครงสร้างข้อมูล Greeks สำหรับ Deribit Options"""
    timestamp: datetime
    instrument_name: str
    underlying_price: float
    mark_price: float
    open_interest: float
    delta: float
    gamma: float
    theta: float
    vega: float
    rho: float
    bid_price: float
    ask_price: float
    bid_iv: float
    ask_iv: float
    data_hash: str = field(default="")
    
    def __post_init__(self):
        # Generate unique hash for deduplication
        raw = f"{self.timestamp}{self.instrument_name}{self.underlying_price}"
        self.data_hash = hashlib.sha256(raw.encode()).hexdigest()[:16]
    
    def validate(self) -> tuple[bool, str]:
        """ตรวจสอบความถูกต้องของข้อมูล"""
        if not (-1 <= self.delta <= 1):
            return False, f"Delta out of range: {self.delta}"
        if self.gamma < 0:
            return False, f"Negative gamma: {self.gamma}"
        if self.theta > 0:
            return False, f"Positive theta for put: {self.theta}"
        if self.vega < 0:
            return False, f"Negative vega: {self.vega}"
        if self.ask_price <= 0 or self.bid_price <= 0:
            return False, "Invalid prices"
        if self.ask_price < self.bid_price:
            return False, f"Ask < Bid: {self.ask_price} < {self.bid_price}"
        return True, "OK"

@dataclass
class DataCompletenessMetrics:
    """Metrics สำหรับติดตาม Data Completeness Rate"""
    total_expected_records: int = 0
    total_actual_records: int = 0
    missing_intervals: List[Dict] = field(default_factory=list)
    duplicate_count: int = 0
    invalid_records: int = 0
    
    @property
    def completeness_rate(self) -> float:
        if self.total_expected_records == 0:
            return 100.0
        return (self.total_actual_records / self.total_expected_records) * 100
    
    @property
    def data_quality_score(self) -> float:
        total = self.total_actual_records
        if total == 0:
            return 0.0
        penalty = (self.duplicate_count + self.invalid_records) / total
        return max(0.0, (1.0 - penalty) * 100)

class DeribitGreeksFetcher:
    """Production-Grade Deribit Greeks Fetcher พร้อม Rate Limiting"""
    
    BASE_URL = "https://www.deribit.com/api/v2/public"
    RATE_LIMIT = 10  # requests per second
    
    def __init__(self, db_pool):
        self.session: Optional[aiohttp.ClientSession] = None
        self.db_pool = db_pool
        self.semaphore = asyncio.Semaphore(self.RATE_LIMIT)
        self.request_timestamps: List[float] = []
        self.metrics = DataCompletenessMetrics()
    
    async def __aenter__(self):
        timeout = aiohttp.ClientTimeout(total=30, connect=10)
        self.session = aiohttp.ClientSession(timeout=timeout)
        return self
    
    async def __aexit__(self, *args):
        if self.session:
            await self.session.close()
    
    async def _rate_limit_wait(self):
        """Implement Token Bucket Rate Limiting"""
        now = asyncio.get_event_loop().time()
        # Remove timestamps older than 1 second
        self.request_timestamps = [ts for ts in self.request_timestamps if now - ts < 1.0]
        
        if len(self.request_timestamps) >= self.RATE_LIMIT:
            oldest = self.request_timestamps[0]
            wait_time = 1.0 - (now - oldest) + 0.01
            if wait_time > 0:
                await asyncio.sleep(wait_time)
        
        self.request_timestamps.append(now)
    
    @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10))
    async def fetch_greeks(self, instrument_name: str) -> Optional[Dict]:
        """ดึงข้อมูล Greeks สำหรับ Instrument เดียว พร้อม Auto-retry"""
        await self._rate_limit_wait()
        
        url = f"{self.BASE_URL}/get_greeks"
        params = {"instrument_name": instrument_name}
        
        try:
            async with self.session.get(url, params=params) as response:
                if response.status == 429:
                    logger.warning(f"Rate limited, backing off...")
                    await asyncio.sleep(5)
                    raise aiohttp.ClientError("Rate limited")
                
                response.raise_for_status()
                data = await response.json()
                
                if data.get("success") and data.get("result"):
                    return data["result"]
                return None
                
        except aiohttp.ClientError as e:
            logger.error(f"Failed to fetch {instrument_name}: {e}")
            raise
    
    async def fetch_greeks_batch(
        self, 
        instruments: List[str],
        on_progress=None
    ) -> List[GreeksRecord]:
        """ดึงข้อมูล Greeks แบบ Batch พร้อม Concurrent Requests"""
        results = []
        total = len(instruments)
        
        async def fetch_one(instrument: str, idx: int):
            try:
                data = await self.fetch_greeks(instrument)
                if data:
                    record = GreeksRecord(
                        timestamp=datetime.utcnow(),
                        instrument_name=instrument,
                        underlying_price=float(data.get("underlying_price", 0)),
                        mark_price=float(data.get("mark_price", 0)),
                        open_interest=float(data.get("open_interest", 0)),
                        delta=float(data.get("delta", 0)),
                        gamma=float(data.get("gamma", 0)),
                        theta=float(data.get("theta", 0)),
                        vega=float(data.get("vega", 0)),
                        rho=float(data.get("rho", 0)),
                        bid_price=float(data.get("bid_price", 0)),
                        ask_price=float(data.get("ask_price", 0)),
                        bid_iv=float(data.get("bid_iv", 0)),
                        ask_iv=float(data.get("ask_iv", 0))
                    )
                    
                    is_valid, msg = record.validate()
                    if not is_valid:
                        self.metrics.invalid_records += 1
                        logger.warning(f"Invalid record {instrument}: {msg}")
                        return None
                    
                    return record
                    
            except Exception as e:
                logger.error(f"Error fetching {instrument}: {e}")
            
            return None
        
        tasks = [fetch_one(inst, idx) for idx, inst in enumerate(instruments)]
        
        for idx, coro in enumerate(asyncio.as_completed(tasks)):
            record = await coro
            if record:
                results.append(record)
            
            if on_progress and (idx + 1) % 100 == 0:
                on_progress(idx + 1, total)
        
        self.metrics.total_actual_records = len(results)
        return results

ตัวอย่างการใช้งาน

async def main(): """Demonstration การดึงข้อมูล Greeks""" # รายการ Instrument ที่ต้องการดึง (BTC Options) instruments = [ f"BTC-{expiry}-{strike}-{ptype}" for expiry in ["25-06", "30-06", "28-07"] for strike in range(60000, 100000, 5000) for ptype in ["P", "C"] ] fetcher = DeribitGreeksFetcher(db_pool=None) # ตั้งค่า DB pool จริง async with fetcher: def progress(current, total): print(f"Progress: {current}/{total} ({current*100/total:.1f}%)") records = await fetcher.fetch_greeks_batch(instruments[:50], on_progress=progress) print(f"\n=== Data Completeness Metrics ===") print(f"Total Records: {fetcher.metrics.total_actual_records}") print(f"Completeness Rate: {fetcher.metrics.completeness_rate:.2f}%") print(f"Data Quality Score: {fetcher.metrics.data_quality_score:.2f}%") print(f"Invalid Records: {fetcher.metrics.invalid_records}") if __name__ == "__main__": asyncio.run(main())

ระบบติดตาม Recalculation Tasks

เมื่อข้อมูล Greeks มีการเปลี่ยนแปลง (เช่น ราคาเปลี่ยน หรือ Implied Volatility เปลี่ยน) ระบบต้อง Recalculate ค่า Greeks ที่เกี่ยวข้องทั้งหมด โดยใช้ Dependency Graph และ Task Queue

Recalculation Task Manager พร้อม Priority Queue

#!/usr/bin/env python3
"""
Recalculation Task Manager สำหรับ Deribit Greeks
รองรับ Priority-based Processing และ Dependency Management
"""
import asyncio
import heapq
from dataclasses import dataclass, field
from typing import Dict, List, Set, Optional, Callable
from datetime import datetime
from enum import Enum
from collections import defaultdict
import redis.asyncio as redis
import json

class TaskPriority(Enum):
    CRITICAL = 1  # สำหรับ Live PnL Calculation
    HIGH = 2      # สำหรับ Risk Management
    MEDIUM = 3    # สำหรับ Historical Analysis
    LOW = 4       # สำหรับ Batch Reports

@dataclass(order=True)
class RecalcTask:
    """Task สำหรับ Recalculate Greeks"""
    priority: int
    task_id: str = field(compare=False)
    instrument_name: str = field(compare=False)
    task_type: str = field(compare=False)  # 'greeks', 'iv_surface', 'portfolio_risk'
    payload: Dict = field(compare=False, default_factory=dict)
    created_at: datetime = field(compare=False, default_factory=datetime.utcnow)
    scheduled_at: Optional[datetime] = field(compare=False, default=None)
    retry_count: int = field(compare=False, default=0)
    max_retries: int = field(compare=False, default=3)
    
    def __post_init__(self):
        self.priority = self.priority.value if isinstance(self.priority, TaskPriority) else self.priority

@dataclass
class StrategyDependency:
    """ข้อมูล Dependency ระหว่าง Strategies และ Greeks Data"""
    strategy_id: str
    strategy_name: str
    required_instruments: Set[str]
    calculation_interval_ms: int
    priority: TaskPriority
    last_recalc: datetime = field(default_factory=datetime.utcnow)
    recalc_count: int = field(default=0)
    failure_count: int = field(default=0)

class DependencyGraph:
    """Directed Acyclic Graph (DAG) สำหรับ Strategy Dependencies"""
    
    def __init__(self):
        self.nodes: Dict[str, StrategyDependency] = {}
        self.edges: Dict[str, Set[str]] = defaultdict(set)  # strategy -> depends_on
        self.reverse_edges: Dict[str, Set[str]] = defaultdict(set)  # strategy -> dependents
    
    def add_strategy(self, strategy: StrategyDependency):
        """เพิ่ม Strategy ในกราฟ"""
        self.nodes[strategy.strategy_id] = strategy
    
    def add_dependency(self, strategy_id: str, depends_on: str):
        """เพิ่ม Dependency (strategy_id ขึ้นอยู่กับ depends_on)"""
        self.edges[strategy_id].add(depends_on)
        self.reverse_edges[depends_on].add(strategy_id)
    
    def get_execution_order(self) -> List[str]:
        """คำนวณ Topological Sort สำหรับ Execution Order"""
        in_degree = {node: 0 for node in self.nodes}
        for deps in self.edges.values():
            for dep in deps:
                if dep in in_degree:
                    in_degree[dep] += 1
        
        queue = [node for node, degree in in_degree.items() if degree == 0]
        heapq.heapify(queue)
        result = []
        
        while queue:
            node = heapq.heappop(queue)
            result.append(node)
            
            for dependent in self.reverse_edges[node]:
                in_degree[dependent] -= 1
                if in_degree[dependent] == 0:
                    heapq.heappush(queue, dependent)
        
        return result
    
    def get_affected_strategies(self, instrument_name: str) -> List[str]:
        """คืนรายการ Strategies ที่จะได้รับผลกระทบจากการเปลี่ยนแstrument"""
        affected = []
        for strategy_id, strategy in self.nodes.items():
            if instrument_name in strategy.required_instruments:
                affected.append(strategy_id)
        return affected

class RecalculationTaskManager:
    """
    Task Manager สำหรับ Greeks Recalculation
    Features:
    - Priority Queue with Deadlines
    - Dependency-aware Scheduling
    - Rate Limiting per Instrument
    - Retry with Exponential Backoff
    """
    
    def __init__(
        self,
        redis_client: redis.Redis,
        max_concurrent: int = 50,
        rate_limit_per_sec: int = 100
    ):
        self.redis = redis_client
        self.max_concurrent = max_concurrent
        self.rate_limit = asyncio.Semaphore(rate_limit_per_sec)
        self.active_tasks: Dict[str, asyncio.Task] = {}
        self.task_queue: List[RecalcTask] = []
        self.dependency_graph = DependencyGraph()
        self.metrics = {
            "total_tasks": 0,
            "completed": 0,
            "failed": 0,
            "pending": 0,
            "avg_latency_ms": 0.0
        }
        self._processing = False
    
    def register_strategy(self, strategy: StrategyDependency):
        """Register Strategy และ Dependencies"""
        self.dependency_graph.add_strategy(strategy)
        
        # Auto-detect dependencies based on overlapping instruments
        for other_id, other_strategy in self.dependency_graph.nodes.items():
            if other_id != strategy.strategy_id:
                overlap = strategy.required_instruments & other_strategy.required_instruments
                if overlap:
                    # Higher priority strategy depends on lower priority
                    if strategy.priority.value < other_strategy.priority.value:
                        self.dependency_graph.add_dependency(
                            strategy.strategy_id, 
                            other_id
                        )
    
    def schedule_task(
        self,
        instrument_name: str,
        task_type: str = "greeks",
        priority: TaskPriority = TaskPriority.MEDIUM,
        payload: Optional[Dict] = None
    ) -> str:
        """Schedule Recalculation Task"""
        task_id = f"{instrument_name}_{task_type}_{datetime.utcnow().timestamp()}"
        
        task = RecalcTask(
            priority=priority,
            task_id=task_id,
            instrument_name=instrument_name,
            task_type=task_type,
            payload=payload or {}
        )
        
        heapq.heappush(self.task_queue, task)
        self.metrics["total_tasks"] += 1
        self.metrics["pending"] += 1
        
        # Cache task for idempotency
        asyncio.create_task(
            self.redis.setex(
                f"task:scheduled:{task_id}",
                3600,
                json.dumps({"priority": priority.value, "created": datetime.utcnow().isoformat()})
            )
        )
        
        return task_id
    
    async def _execute_task(self, task: RecalcTask, executor: Callable) -> bool:
        """Execute Single Task พร้อม Error Handling"""
        start_time = asyncio.get_event_loop().time()
        
        try:
            async with self.rate_limit:
                await executor(task)
                
                # Update metrics
                latency_ms = (asyncio.get_event_loop().time() - start_time) * 1000
                self.metrics["completed"] += 1
                self.metrics["pending"] -= 1
                self.metrics["avg_latency_ms"] = (
                    (self.metrics["avg_latency_ms"] * (self.metrics["completed"] - 1) + latency_ms) 
                    / self.metrics["completed"]
                )
                
                # Update Strategy metrics
                affected = self.dependency_graph.get_affected_strategies(task.instrument_name)
                for strategy_id in affected:
                    strategy = self.dependency_graph.nodes[strategy_id]
                    strategy.last_recalc = datetime.utcnow()
                    strategy.recalc_count += 1
                
                return True
                
        except Exception as e:
            self.metrics["failed"] += 1
            self.metrics["pending"] -= 1
            
            # Retry logic
            if task.retry_count < task.max_retries:
                task.retry_count += 1
                backoff = 2 ** task.retry_count
                task.scheduled_at = datetime.utcnow()
                asyncio.create_task(
                    asyncio.sleep(backoff),
                    name=f"retry_{task.task_id}"
                )
                heapq.heappush(self.task_queue, task)
                self.metrics["pending"] += 1
            
            return False
    
    async def process_queue(self, executor: Callable):
        """Process Task Queue Continuously"""
        self._processing = True
        
        while self._processing:
            # Get next task
            if not self.task_queue:
                await asyncio.sleep(0.1)
                continue
            
            # Check concurrent limit
            if len(self.active_tasks) >= self.max_concurrent:
                await asyncio.sleep(0.1)
                continue
            
            task = heapq.heappop(self.task_queue)
            task_coroutine = self._execute_task(task, executor)
            self.active_tasks[task.task_id] = asyncio.create_task(task_coroutine)
            
            # Clean up completed tasks
            done = [tid for tid, t in self.active_tasks.items() if t.done()]
            for tid in done:
                del self.active_tasks[tid]
    
    def get_metrics(self) -> Dict:
        """คืนค่า Metrics สำหรับ Dashboard"""
        return {
            **self.metrics,
            "queue_size": len(self.task_queue),
            "active_tasks": len(self.active_tasks),
            "strategies": {
                sid: {
                    "name": s.strategy_name,
                    "last_recalc": s.last_recalc.isoformat(),
                    "recalc_count": s.recalc_count,
                    "failure_count": s.failure_count
                }
                for sid, s in self.dependency_graph.nodes.items()
            }
        }

ตัวอย่างการใช้งาน

async def example_usage(): redis_client = await redis.from_url("redis://localhost:6379/0") manager = RecalculationTaskManager(redis_client) # Register Strategies strategies = [ StrategyDependency( strategy_id="strat_001", strategy_name="Delta Hedging Bot", required_instruments={"BTC-25-06-60000-P", "BTC-25-06-65000-C"}, calculation_interval_ms=100, priority=TaskPriority.CRITICAL ), StrategyDependency( strategy_id="strat_002", strategy_name="Gamma Scalping", required_instruments={"BTC-25-06-60000-P", "BTC-25-06-62000-P"}, calculation_interval_ms=500, priority=TaskPriority.HIGH ) ] for strategy in strategies: manager.register_strategy(strategy) # Schedule Tasks manager.schedule_task( "BTC-25-06-60000-P", task_type="greeks", priority=TaskPriority.HIGH ) # Process queue async def task_executor(task: RecalcTask): # Simulate calculation await asyncio.sleep(0.05) print(f"Executed: {task.task_id}") await manager.process_queue(task_executor) if __name__ == "__main__": asyncio.run(example_usage())

Integration กับ HolySheep AI สำหรับ Smart Analysis

ในการวิเคราะห์ Greeks Data และสร้าง Alert อัตโนมัติ เราสามารถใช้ HolySheep AI ซึ่งมีความเร็ว <50ms และราคาประหยัดถึง 85%+ เมื่อเทียบกับ OpenAI โดยใช้ base_url: https://api.holysheep.ai/v1

#!/usr/bin/env python3
"""
HolySheep AI Integration สำหรับ Deribit Greeks Analysis
ใช้ base_url: https://api.holysheep.ai/v1
"""
import httpx
import json
from typing import Dict, List, Optional
from datetime import datetime
from dataclasses import dataclass

HolySheep API Configuration

HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1" API_KEY = "YOUR_HOLYSHEEP_API_KEY" # ได้จาก https://www.holysheep.ai/register @dataclass class GreeksAnalysis: """ผลลัพธ์การวิเคราะห์ Greeks จาก AI""" summary: str alerts: List[Dict] risk_score: float recommendations: List[str] confidence: float class HolySheepAIClient: """Client สำหรับเชื่อมต่อ HolySheep AI API""" def __init__(self, api_key: str = API_KEY): self.api_key = api_key self.base_url = HOLYSHEEP_BASE_URL self.client = httpx.AsyncClient( timeout=httpx.Timeout(30.0), limits=httpx.Limits(max_connections=100) ) async def analyze_greeks_data( self, greeks_records: List[Dict], analysis_type: str = "risk" ) -> GreeksAnalysis: """ วิเคราะห์ Greeks Data ด้วย HolySheep AI Args: greeks_records: รายการข้อมูล Greeks ที่ต้องการวิเคราะห์ analysis_type: "risk" | "opportunity" | "general" """ # Prepare context avg_delta = sum(r.get("delta", 0) for r in greeks_records) / len(greeks_records) avg_gamma = sum(r.get("gamma", 0) for r in greeks_records) / len(greeks_records) avg_theta = sum(r.get("theta", 0) for r in greeks_records) / len(greeks_records) avg_vega = sum(r.get("vega", 0) for r in greeks_records) / len(greeks_records) prompt = f"""Analyze Deribit Options Greeks Data: Summary Statistics: - Average Delta: {avg_delta:.4f} - Average Gamma: {avg_gamma:.6f} - Average Theta: {avg_theta:.4f} - Average Vega: {avg_vega:.4f} - Total Records: {len(greeks_records)} Instruments: {[r.get('instrument_name') for r in greeks_records[:10]]} Provide: 1. Risk Assessment (0-100) 2. Key Alerts (if any) 3. Recommendations for traders 4. Confidence level (0-100) """ response = await self._call_model( prompt=prompt, system="You are a professional options trader and risk analyst. Provide concise, actionable insights." ) return GreeksAnalysis( summary=response.get("summary", ""), alerts=response.get("alerts", []), risk_score=response.get("risk_score", 50.0), recommendations=response.get("recommendations", []), confidence=response.get("confidence", 0.0) ) async def generate_anomaly_alert( self, instrument: str, current_greeks: Dict, historical_avg: Dict, threshold_multiplier: float = 2.0 ) -> Optional[Dict]: """ตรวจจับ Anomaly ในข้อมูล Greeks และสร้าง Alert""" anomalies = [] for key in ["delta", "gamma", "theta", "vega"]: current = current_greeks.get(key, 0) hist = historical_avg.get(key, 0) if hist != 0: change_pct = abs((current - hist) / hist) * 100 if change_pct > threshold_multiplier * 100: anomalies.append({ "metric": key, "current": current, "historical_avg": hist, "change_percent": change_pct }) if anomalies: prompt = f"""Anomaly detected in {instrument} Greeks Data: Anomalies Found: {json.dumps(anomalies, indent=2)} Current Market Context: - Underlying Price: {current_greeks.get('underlying_price')} - Mark Price: {current_greeks.get('mark_price')} - Open Interest: {current_greeks.get('open_interest')} Generate an alert message that includes: 1. Severity level (LOW/MEDIUM/HIGH/CRITICAL) 2. Probable cause 3. Recommended action """ response = await self._call_model( prompt=prompt, system="You are a risk monitoring system. Generate clear, actionable alerts." ) return { "instrument": instrument, "anomalies": anomalies, "alert_message": response.get("alert_message", "Anomaly detected"), "severity": response.get("severity", "MEDIUM"), "timestamp": datetime.utcnow().isoformat() } return None async def generate_research_report( self, greeks_data: List[Dict], team_satisfaction_metrics: Dict ) -> str: """สร้าง Research Report อัตโนมัติสำหรับทีมวิจัย""" prompt = f"""Generate a comprehensive research report based on: Greeks Data Summary: - Total Instruments: {len(greeks_data)} - Time Range: {greeks_data[0].get('timestamp')} to {greeks_data[-1].get('timestamp')} Team Satisfaction Metrics: - Data Quality Score: {team_satisfaction_metrics.get('data_quality_score',