Trong thế giới fintechalgorithmic trading, dữ liệu lịch sử là vàng. Một chiến lược giao dịch có thể tạo ra lợi nhuận triệu đô — nhưng nếu không có cách kiểm tra lại trên dữ liệu quá khứ một cách chính xác, rủi ro thua lỗ là cực kỳ cao. Bài viết này sẽ hướng dẫn bạn xây dựng Tardis Machine — một local replay server mạnh mẽ sử dụng Python và Node.js — để tái tạo và phân tích dữ liệu thị trường một cách đáng tin cậy.

Nghiên Cứu Điển Hình: Startup AI Tại Hà Nội Tiết Kiệm $3,520/tháng

Bối cảnh: Một startup AI tại Hà Nội chuyên phát triển bot giao dịch tự động đã sử dụng dịch vụ replay server từ nhà cung cấp nước ngoài trong suốt 18 tháng. Hệ thống của họ xử lý khoảng 50 triệu tick dữ liệu mỗi ngày cho 12 cặp tiền tệ và 5 loại tiền điện tử.

Điểm đau: Server cũ gặp vấn đề nghiêm trọng: độ trễ trung bình 420ms mỗi khi replay, chi phí hàng tháng lên tới $4,200, và thường xuyên timeout khi xử lý khối lượng lớn. Đội ngũ kỹ thuật phải chờ đợi hàng giờ để backtest một chiến lược đơn giản.

Giải pháp HolySheep: Sau khi migration sang kiến trúc Tardis Machine kết hợp HolySheep AI, startup này đã đạt được kết quả ngoài mong đợi. Quá trình di chuyển bao gồm: đổi base_url từ API cũ sang https://api.holysheep.ai/v1, xoay API key mới, và triển khai canary deployment để đảm bảo zero-downtime.

Kết quả sau 30 ngày go-live:

Chỉ sốTrước migrationSau migrationCải thiện
Độ trễ trung bình420ms180ms57%
Chi phí hàng tháng$4,200$68084%
Thời gian backtest 1 chiến lược4.5 giờ45 phút83%
Uptime97.2%99.8%+2.6%

Tardis Machine Là Gì?

Tardis Machine là một local replay server được thiết kế để tái tạo dữ liệu thị trường theo thời gian thực hoặc theo đơn vị accelerated time. Thay vì phụ thuộc vào API bên ngoài với giới hạn rate và chi phí cao, bạn có thể:

Kiến Trúc Hệ Thống

Chúng ta sẽ xây dựng hệ thống với 3 thành phần chính:

Cài Đặt Môi Trường

Yêu Cầu Hệ Thống

# Cài đặt Python dependencies
pip install pandas numpy asyncio aiohttp fastapi uvicorn
pip install python-dotenv redis asyncpg sqlalchemy

Cài đặt Node.js dependencies

mkdir tardis-machine && cd tardis-machine npm init -y npm install express ws ioredis pg dotenv npm install -D typescript @types/node ts-node nodemon

Phần 1: Data Layer với Python

Data Layer chịu trách nhiệm tải, lưu trữ và truy xuất dữ liệu thị trường. Chúng ta sẽ sử dụng async/await pattern để đảm bảo hiệu suất cao.

# data_layer/config.py
import os
from dotenv import load_dotenv

load_dotenv()

HolySheep AI Configuration

HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY") HOLYSHEEP_BASE_URL = "https://api.holysheep.ai/v1"

Database Configuration

DB_HOST = os.getenv("DB_HOST", "localhost") DB_PORT = int(os.getenv("DB_PORT", "5432")) DB_NAME = os.getenv("DB_NAME", "tardis_data") DB_USER = os.getenv("DB_USER", "postgres") DB_PASSWORD = os.getenv("DB_PASSWORD", "postgres")

Redis Configuration

REDIS_HOST = os.getenv("REDIS_HOST", "localhost") REDIS_PORT = int(os.getenv("REDIS_PORT", "6379"))

Replay Configuration

DEFAULT_SPEED = 1.0 # 1x, 10x, 100x BATCH_SIZE = 1000 CACHE_TTL = 3600 # 1 hour
# data_layer/models.py
from dataclasses import dataclass
from datetime import datetime
from typing import Optional, List
from enum import Enum
import pandas as pd

class DataType(Enum):
    OHLCV = "ohlcv"
    TICK = "tick"
    ORDERBOOK = "orderbook"
    TRADE = "trade"

@dataclass
class OHLCV:
    timestamp: datetime
    symbol: str
    open: float
    high: float
    low: float
    close: float
    volume: float
    
    def to_dict(self):
        return {
            "timestamp": self.timestamp.isoformat(),
            "symbol": self.symbol,
            "open": self.open,
            "high": self.high,
            "low": self.low,
            "close": self.close,
            "volume": self.volume
        }

@dataclass
class Tick:
    timestamp: datetime
    symbol: str
    price: float
    volume: float
    side: str  # 'buy' or 'sell'
    
    def to_dict(self):
        return {
            "timestamp": self.timestamp.isoformat(),
            "symbol": self.symbol,
            "price": self.price,
            "volume": self.volume,
            "side": self.side
        }

@dataclass
class ReplayEvent:
    event_id: str
    timestamp: datetime
    data_type: DataType
    payload: dict
    sequence: int
    
    def to_dict(self):
        return {
            "event_id": self.event_id,
            "timestamp": self.timestamp.isoformat(),
            "data_type": self.data_type.value,
            "payload": self.payload,
            "sequence": self.sequence
        }
# data_layer/storage.py
import asyncio
import asyncpg
import json
from datetime import datetime, timedelta
from typing import List, Optional, AsyncGenerator
from pathlib import Path
import pandas as pd

from .models import OHLCV, Tick, ReplayEvent, DataType
from .config import DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD, BATCH_SIZE

class DataStorage:
    def __init__(self):
        self.pool: Optional[asyncpg.Pool] = None
        
    async def connect(self):
        """Khởi tạo kết nối database"""
        self.pool = await asyncpg.create_pool(
            host=DB_HOST,
            port=DB_PORT,
            database=DB_NAME,
            user=DB_USER,
            password=DB_PASSWORD,
            min_size=5,
            max_size=20
        )
        await self.init_tables()
        
    async def init_tables(self):
        """Tạo bảng nếu chưa tồn tại"""
        async with self.pool.acquire() as conn:
            await conn.execute('''
                CREATE TABLE IF NOT EXISTS ohlcv_data (
                    id SERIAL PRIMARY KEY,
                    symbol VARCHAR(20) NOT NULL,
                    timestamp TIMESTAMPTZ NOT NULL,
                    open NUMERIC(18, 8) NOT NULL,
                    high NUMERIC(18, 8) NOT NULL,
                    low NUMERIC(18, 8) NOT NULL,
                    close NUMERIC(18, 8) NOT NULL,
                    volume NUMERIC(18, 8) NOT NULL,
                    created_at TIMESTAMPTZ DEFAULT NOW(),
                    UNIQUE(symbol, timestamp)
                );
                
                CREATE INDEX IF NOT EXISTS idx_ohlcv_symbol_timestamp 
                ON ohlcv_data(symbol, timestamp);
                
                CREATE TABLE IF NOT EXISTS tick_data (
                    id SERIAL PRIMARY KEY,
                    symbol VARCHAR(20) NOT NULL,
                    timestamp TIMESTAMPTZ NOT NULL,
                    price NUMERIC(18, 8) NOT NULL,
                    volume NUMERIC(18, 8) NOT NULL,
                    side VARCHAR(4) NOT NULL,
                    created_at TIMESTAMPTZ DEFAULT NOW()
                );
                
                CREATE INDEX IF NOT EXISTS idx_tick_symbol_timestamp 
                ON tick_data(symbol, timestamp);
                
                CREATE TABLE IF NOT EXISTS replay_events (
                    id SERIAL PRIMARY KEY,
                    event_id VARCHAR(50) UNIQUE NOT NULL,
                    timestamp TIMESTAMPTZ NOT NULL,
                    data_type VARCHAR(20) NOT NULL,
                    payload JSONB NOT NULL,
                    sequence BIGINT NOT NULL
                );
                
                CREATE INDEX IF NOT EXISTS idx_events_timestamp 
                ON replay_events(timestamp);
            ''')
            
    async def store_ohlcv(self, data: List[OHLCV]):
        """Lưu trữ dữ liệu OHLCV theo batch"""
        async with self.pool.acquire() as conn:
            values = [
                (d.symbol, d.timestamp, d.open, d.high, d.low, d.close, d.volume)
                for d in data
            ]
            await conn.executemany('''
                INSERT INTO ohlcv_data (symbol, timestamp, open, high, low, close, volume)
                VALUES ($1, $2, $3, $4, $5, $6, $7)
                ON CONFLICT (symbol, timestamp) DO UPDATE SET
                    open = EXCLUDED.open,
                    high = EXCLUDED.high,
                    low = EXCLUDED.low,
                    close = EXCLUDED.close,
                    volume = EXCLUDED.volume
            ''', values)
            
    async def store_ticks(self, data: List[Tick]):
        """Lưu trữ tick data theo batch"""
        async with self.pool.acquire() as conn:
            values = [
                (d.symbol, d.timestamp, d.price, d.volume, d.side)
                for d in data
            ]
            await conn.executemany('''
                INSERT INTO tick_data (symbol, timestamp, price, volume, side)
                VALUES ($1, $2, $3, $4, $5)
            ''', values)
            
    async def get_ohlcv_range(
        self, 
        symbol: str, 
        start: datetime, 
        end: datetime
    ) -> List[OHLCV]:
        """Lấy dữ liệu OHLCV trong khoảng thời gian"""
        async with self.pool.acquire() as conn:
            rows = await conn.fetch('''
                SELECT symbol, timestamp, open, high, low, close, volume
                FROM ohlcv_data
                WHERE symbol = $1 AND timestamp >= $2 AND timestamp <= $3
                ORDER BY timestamp ASC
            ''', symbol, start, end)
            
            return [
                OHLCV(
                    timestamp=row['timestamp'],
                    symbol=row['symbol'],
                    open=float(row['open']),
                    high=float(row['high']),
                    low=float(row['low']),
                    close=float(row['close']),
                    volume=float(row['volume'])
                )
                for row in rows
            ]
            
    async def stream_events(
        self,
        start: datetime,
        end: datetime,
        batch_size: int = BATCH_SIZE
    ) -> AsyncGenerator[List[ReplayEvent], None]:
        """Stream events theo batch để tiết kiệm memory"""
        offset = 0
        while True:
            async with self.pool.acquire() as conn:
                rows = await conn.fetch('''
                    SELECT event_id, timestamp, data_type, payload, sequence
                    FROM replay_events
                    WHERE timestamp >= $1 AND timestamp <= $2
                    ORDER BY sequence ASC
                    LIMIT $3 OFFSET $4
                ''', start, end, batch_size, offset)
                
                if not rows:
                    break
                    
                events = [
                    ReplayEvent(
                        event_id=row['event_id'],
                        timestamp=row['timestamp'],
                        data_type=DataType(row['data_type']),
                        payload=row['payload'],
                        sequence=row['sequence']
                    )
                    for row in rows
                ]
                yield events
                offset += batch_size
                
    async def close(self):
        """Đóng kết nối"""
        if self.pool:
            await self.pool.close()

Phần 2: Replay Engine với Node.js

Replay Engine là trái tim của Tardis Machine — nơi xử lý timing, synchronization và giao tiếp real-time với client.

// replay-engine/src/types.ts
export enum DataType {
  OHLCV = 'ohlcv',
  TICK = 'tick',
  ORDERBOOK = 'orderbook',
  TRADE = 'trade'
}

export interface OHLCVData {
  timestamp: string;
  symbol: string;
  open: number;
  high: number;
  low: number;
  close: number;
  volume: number;
}

export interface TickData {
  timestamp: string;
  symbol: string;
  price: number;
  volume: number;
  side: 'buy' | 'sell';
}

export interface ReplayEvent {
  event_id: string;
  timestamp: string;
  data_type: DataType;
  payload: Record;
  sequence: number;
}

export interface ReplaySession {
  session_id: string;
  start_time: Date;
  end_time: Date;
  speed: number;
  status: 'running' | 'paused' | 'stopped' | 'completed';
  current_timestamp: Date;
  events_processed: number;
}

export interface ReplayConfig {
  session_id: string;
  start_time: string;
  end_time: string;
  speed: number;
  symbols: string[];
  data_types: DataType[];
}
// replay-engine/src/replay-engine.ts
import { EventEmitter } from 'events';
import WebSocket from 'ws';
import axios from 'axios';
import { ReplaySession, ReplayConfig, ReplayEvent, DataType } from './types';

// HolySheep AI Configuration
const HOLYSHEEP_BASE_URL = 'https://api.holysheep.ai/v1';
const HOLYSHEEP_API_KEY = process.env.HOLYSHEEP_API_KEY || 'YOUR_HOLYSHEEP_API_KEY';

export class ReplayEngine extends EventEmitter {
  private session: ReplaySession | null = null;
  private config: ReplayConfig | null = null;
  private wsServer: WebSocket.Server | null = null;
  private pythonApiUrl: string;
  private speed: number = 1.0;
  private isPaused: boolean = false;
  private eventBuffer: ReplayEvent[] = [];
  private processingInterval: NodeJS.Timeout | null = null;
  
  constructor(pythonApiUrl: string = 'http://localhost:8000') {
    super();
    this.pythonApiUrl = pythonApiUrl;
  }
  
  async start(config: ReplayConfig): Promise {
    console.log([Tardis] Khởi động Replay Engine với tốc độ ${config.speed}x);
    
    this.config = config;
    this.speed = config.speed;
    this.isPaused = false;
    
    this.session = {
      session_id: config.session_id,
      start_time: new Date(config.start_time),
      end_time: new Date(config.end_time),
      speed: config.speed,
      status: 'running',
      current_timestamp: new Date(config.start_time),
      events_processed: 0
    };
    
    // Bắt đầu fetch và replay events
    this.startEventFetcher();
    
    return this.session;
  }
  
  private async startEventFetcher(): Promise {
    if (!this.config || !this.session) return;
    
    const fetchInterval = 1000 / this.speed; // Điều chỉnh interval theo speed
    
    this.processingInterval = setInterval(async () => {
      if (this.isPaused) return;
      
      try {
        // Gọi Python API để lấy batch events
        const response = await axios.post(
          ${this.pythonApiUrl}/api/events/stream,
          {
            start_time: this.session!.current_timestamp.toISOString(),
            end_time: this.session!.end_time.toISOString(),
            batch_size: Math.floor(100 * this.speed), // Tăng batch khi speed cao
            symbols: this.config!.symbols
          },
          { timeout: 5000 }
        );
        
        const events: ReplayEvent[] = response.data.events;
        
        if (events.length === 0) {
          this.session.status = 'completed';
          this.emit('complete', this.session);
          this.stop();
          return;
        }
        
        // Xử lý từng event
        for (const event of events) {
          await this.processEvent(event);
        }
        
        // Cập nhật session
        this.session.current_timestamp = new Date(events[events.length - 1].timestamp);
        this.session.events_processed += events.length;
        
        // Gửi heartbeat cho client
        this.emit('progress', {
          current_timestamp: this.session.current_timestamp,
          events_processed: this.session.events_processed,
          progress: this.calculateProgress()
        });
        
      } catch (error) {
        console.error('[Tardis] Lỗi fetch events:', error.message);
        this.emit('error', error);
      }
    }, fetchInterval);
  }
  
  private async processEvent(event: ReplayEvent): Promise {
    // Gửi event tới tất cả WebSocket clients
    this.broadcast(event);
    
    // Tích hợp AI analysis cho certain data types
    if (event.data_type === DataType.OHLCV || event.data_type === DataType.TICK) {
      await this.analyzeWithAI(event);
    }
    
    this.emit('event', event);
  }
  
  private async analyzeWithAI(event: ReplayEvent): Promise {
    try {
      // Sử dụng HolySheep AI để phân tích
      const response = await axios.post(
        ${HOLYSHEEP_BASE_URL}/chat/completions,
        {
          model: 'deepseek-v3.2', // Model giá rẻ nhất: $0.42/MTok
          messages: [
            {
              role: 'system',
              content: 'Bạn là một chuyên gia phân tích thị trường tài chính.'
            },
            {
              role: 'user',
              content: Phân tích dữ liệu thị trường sau và đưa ra nhận định ngắn gọn:\n${JSON.stringify(event.payload)}
            }
          ],
          max_tokens: 100,
          temperature: 0.3
        },
        {
          headers: {
            'Authorization': Bearer ${HOLYSHEEP_API_KEY},
            'Content-Type': 'application/json'
          },
          timeout: 1000 // 1 second timeout cho real-time
        }
      );
      
      const analysis = response.data.choices[0].message.content;
      
      // Gửi kết quả phân tích tới clients
      this.emit('analysis', {
        event_id: event.event_id,
        analysis: analysis,
        model: 'deepseek-v3.2',
        cost: response.data.usage.total_tokens * 0.00042 // ~$0.00042 cho 100 tokens
      });
      
    } catch (error) {
      // Không block replay nếu AI analysis thất bại
      console.warn([Tardis] AI analysis failed for ${event.event_id});
    }
  }
  
  private broadcast(event: ReplayEvent): void {
    if (!this.wsServer) return;
    
    const message = JSON.stringify({
      type: 'event',
      data: event
    });
    
    this.wsServer.clients.forEach(client => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  }
  
  private calculateProgress(): number {
    if (!this.session) return 0;
    
    const total = this.session.end_time.getTime() - this.session.start_time.getTime();
    const current = this.session.current_timestamp.getTime() - this.session.start_time.getTime();
    
    return Math.min(100, (current / total) * 100);
  }
  
  pause(): void {
    this.isPaused = true;
    if (this.session) {
      this.session.status = 'paused';
    }
    console.log('[Tardis] Replay paused');
  }
  
  resume(): void {
    this.isPaused = false;
    if (this.session) {
      this.session.status = 'running';
    }
    console.log('[Tardis] Replay resumed');
  }
  
  stop(): void {
    if (this.processingInterval) {
      clearInterval(this.processingInterval);
      this.processingInterval = null;
    }
    if (this.session) {
      this.session.status = 'stopped';
    }
    console.log('[Tardis] Replay stopped');
  }
  
  setSpeed(speed: number): void {
    this.speed = speed;
    if (this.session) {
      this.session.speed = speed;
    }
    console.log([Tardis] Speed changed to ${speed}x);
  }
  
  getSession(): ReplaySession | null {
    return this.session;
  }
  
  attachWebSocket(server: WebSocket.Server): void {
    this.wsServer = server;
  }
}
// replay-engine/src/server.ts
import express from 'express';
import { createServer } from 'http';
import { WebSocketServer, WebSocket } from 'ws';
import { ReplayEngine } from './replay-engine';
import { ReplayConfig } from './types';

const app = express();
const server = createServer(app);
const wss = new WebSocketServer({ server });

const engine = new ReplayEngine('http://localhost:8000');
engine.attachWebSocket(wss);

// Middleware
app.use(express.json());

// WebSocket connection handling
wss.on('connection', (ws: WebSocket) => {
  console.log('[WS] Client connected');
  
  ws.on('message', (message: string) => {
    try {
      const data = JSON.parse(message);
      
      switch (data.type) {
        case 'start':
          handleStartReplay(data.config, ws);
          break;
        case 'pause':
          engine.pause();
          break;
        case 'resume':
          engine.resume();
          break;
        case 'stop':
          engine.stop();
          break;
        case 'speed':
          engine.setSpeed(data.speed);
          break;
        case 'seek':
          handleSeek(data.timestamp);
          break;
      }
    } catch (error) {
      ws.send(JSON.stringify({ type: 'error', message: 'Invalid message format' }));
    }
  });
  
  ws.on('close', () => {
    console.log('[WS] Client disconnected');
  });
});

async function handleStartReplay(config: ReplayConfig, ws: WebSocket) {
  try {
    const session = await engine.start(config);
    
    // Subscribe to engine events
    engine.on('progress', (data) => {
      ws.send(JSON.stringify({ type: 'progress', ...data }));
    });
    
    engine.on('analysis', (data) => {
      ws.send(JSON.stringify({ type: 'analysis', ...data }));
    });
    
    engine.on('complete', (session) => {
      ws.send(JSON.stringify({ type: 'complete', session }));
    });
    
    engine.on('error', (error) => {
      ws.send(JSON.stringify({ type: 'error', message: error.message }));
    });
    
    ws.send(JSON.stringify({ type: 'started', session }));
  } catch (error) {
    ws.send(JSON.stringify({ type: 'error', message: error.message }));
  }
}

function handleSeek(timestamp: string) {
  engine.stop();
  // Implement seek logic here
  console.log([Tardis] Seek to ${timestamp});
}

// REST API endpoints
app.get('/api/health', (req, res) => {
  res.json({ status: 'healthy', engine: engine.getSession()?.status || 'idle' });
});

app.get('/api/session', (req, res) => {
  res.json(engine.getSession());
});

app.post('/api/control', (req, res) => {
  const { action, speed } = req.body;
  
  switch (action) {
    case 'pause':
      engine.pause();
      break;
    case 'resume':
      engine.resume();
      break;
    case 'stop':
      engine.stop();
      break;
    case 'speed':
      if (speed) engine.setSpeed(speed);
      break;
  }
  
  res.json({ success: true, session: engine.getSession() });
});

const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log([Tardis] Replay Engine running on port ${PORT});
});

Phần 3: Tích Hợp HolySheep AI

HolySheep AI là lựa chọn tối ưu cho việc phân tích dữ liệu thị trường real-time vì:

# ai_integration/analyzer.py
import asyncio
import aiohttp
import json
from typing import Dict, List, Optional
from datetime import datetime
from dataclasses import dataclass

from data_layer.config import HOLYSHEEP_BASE_URL, HOLYSHEEP_API_KEY
from data_layer.models import OHLCV, Tick

@dataclass
class AnalysisResult:
    timestamp: datetime
    symbol: str
    pattern: str
    signal: str  # 'bullish', 'bearish', 'neutral'
    confidence: float
    summary: str
    cost: float

class MarketAnalyzer:
    def __init__(self):
        self.api_key = HOLYSHEEP_API_KEY
        self.base_url = HOLYSHEEP_BASE_URL
        self.session: Optional[aiohttp.ClientSession] = None
        
    async def initialize(self):
        """Khởi tạo aiohttp session"""
        self.session = aiohttp.ClientSession(
            headers={
                'Authorization': f'Bearer {self.api_key}',
                'Content-Type': 'application/json'
            }
        )
        
    async def close(self):
        """Đóng session"""
        if self.session:
            await self.session.close()
            
    async def analyze_ohlcv(
        self, 
        data: List[OHLCV],
        model: str = 'deepseek-v3.2'
    ) -> AnalysisResult:
        """Phân tích dữ liệu OHLCV với AI"""
        
        # Chuẩn bị prompt với dữ liệu
        prompt = self._build_analysis_prompt(data)
        
        try:
            async with self.session.post(
                f'{self.base_url}/chat/completions',
                json={
                    'model': model,
                    'messages': [
                        {
                            'role': 'system',
                            'content': '''Bạn là chuyên gia phân tích kỹ thuật thị trường tài chính.
Hãy phân tích dữ liệu OHLCV và đưa ra:
1. Pattern nhận diện được (VD: Double Bottom, Head & Shoulders, etc.)
2. Tín hiệu (bullish/bearish/neutral)
3. Mức độ tin cậy (0-100%)
4. Tóm tắt ngắn gọn 2-3 câu'''
                        },
                        {
                            'role': 'user',
                            'content': prompt
                        }
                    ],
                    'max_tokens': 200,
                    'temperature': 0.3
                },
                timeout=aiohttp.ClientTimeout(total=2.0)  # 2 second timeout
            ) as response:
                result = await response.json()
                
                # Parse response
                content = result['choices'][0]['message']['content']
                usage = result['usage']
                
                # Calculate cost (token count * price per 1M tokens)
                cost_per_million = {
                    'gpt-4.1': 8.0,
                    'claude-sonnet-4.5': 15.0,
                    'gemini-2.5-flash': 2.50,
                    'deepseek-v3.2': 0.42
                }
                cost = (usage['total_tokens'] / 1_000_000) * cost_per_million.get(model, 0.42)
                
                return self._parse_analysis_result(content, data, cost)
                
        except asyncio.TimeoutError:
            print(f'[Analyzer] Timeout khi gọi AI cho {data[0].symbol if data else "unknown"}')
            return self._create_fallback_result(data)
        except Exception as e:
            print(f'[Analyzer] Lỗi: {e}')
            return self._create_fallback_result(data)
            
    def _build_analysis_prompt(self, data: List[OHLCV]) -> str:
        """Build prompt từ OHLCV data"""
        lines = ['Dữ liệu OHLCV 10 nến gần nhất:']
        
        for candle in data[-10:]:
            lines.append(
                f"- {candle.timestamp.strftime('%Y-%m-%d %H:%M')}: "
                f"O={candle.open:.2f} H={candle.high:.2f} "
                f"L={candle.low:.2f} C={candle.close:.2f} V={candle.volume:.0f}"
            )
            
        lines.append(f'\nGiá hiện tại: {data[-1].close if data else 0}')
        lines.append(f'Symbol: {data[0].symbol if data else "UNKNOWN"}')
        
        return '\n'.join(lines)
        
    def _parse_analysis_result(
        self, 
        content: str, 
        data: List[OHLCV],
        cost: float
    ) -> AnalysisResult:
        """Parse kết quả từ AI response"""
        # Simple parsing - trong thực tế nên dùng structured output
        signal = 'neutral'
        if any(word in content.lower() for word in ['bull', 'tăng', 'mua', 'long']):
            signal = 'bullish'
        elif any(word in content.lower() for word in ['bear', 'giảm', 'bán', 'short']):
            signal = 'bearish'
            
        confidence = 50.0  # Default confidence
        
        return AnalysisResult(