Trong thế giới fintech và algorithmic 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 migration | Sau migration | Cải thiện |
|---|---|---|---|
| Độ trễ trung bình | 420ms | 180ms | 57% |
| Chi phí hàng tháng | $4,200 | $680 | 84% |
| Thời gian backtest 1 chiến lược | 4.5 giờ | 45 phút | 83% |
| Uptime | 97.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ể:
- Tải toàn bộ dữ liệu lịch sử về local server
- Replay với tốc độ có thể điều chỉnh (1x, 10x, 100x)
- Tích hợp AI để phân tích pattern và đưa ra dự đoán
- Backtest chiến lược giao dịch với độ chính xác cao
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:
- Data Layer (Python): Quản lý dữ liệu OHLCV, tick-by-tick data, order book snapshots
- Replay Engine (Node.js): Xử lý replay events, quản lý timing và synchronization
- AI Integration (HolySheep API): Phân tích dữ liệu thời gian thực với chi phí cực thấp
Cài Đặt Môi Trường
Yêu Cầu Hệ Thống
- Python 3.9+ với pip
- Node.js 18+ với npm
- 4GB RAM tối thiểu (8GB khuyến nghị)
- 50GB disk space cho dữ liệu lịch sử
# 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ì:
- Chi phí cực thấp: DeepSeek V3.2 chỉ $0.42/MTok — tiết kiệm 85%+ so với GPT-4.1 ($8/MTok)
- Độ trễ thấp: Trung bình <50ms cho inference
- Hỗ trợ thanh toán: WeChat, Alipay, Visa, Mastercard
- Tín dụng miễn phí: Khi đăng ký tài khoản mới
# 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(