Trong thị trường crypto, mỗi mili-giây đều có ý nghĩa. Việc phân tích L2 Order Book (sổ lệnh mức 2) giúp nhà giao dịch hiểu rõ áp lực mua/bán, dự đoán điểm break-out và tối ưu hóa chiến lược. Bài viết này sẽ hướng dẫn bạn cách sử dụng Tardis API để tải historical tick data và xây dựng hệ thống phân tích micro-structure hoàn chỉnh.

Tại sao L2 Order Book quan trọng với trader BTC/ETH?

L2 Order Book cung cấp thông tin chi tiết về các lệnh đặt mua/bán ở mỗi mức giá. Khác với chỉ báo thuần túy (RSI, MACD), Order Book cho thấy "dòng tiền thật sự" đang ở đâu:

Kiến trúc hệ thống回测

┌─────────────────────────────────────────────────────────────┐
│                    Tardis API                               │
│  Historical Tick Data → Real-time WebSocket → Replay       │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│               Data Processing Layer                          │
│  ├── Parse L2 Update (bids/asks snapshot)                   │
│  ├── Calculate OFI (Order Flow Imbalance)                    │
│  ├── Compute VWAP, TWAP at micro-level                      │
│  └── Detect Iceberg Orders (hidden liquidity)                │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│               Strategy Engine                                │
│  ├── Mean Reversion on L2 Imbalance                         │
│  ├── Momentum on Large Bid/Ask Ratio                        │
│  └── Break-out on Order Book Unfolding                      │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│               Backtest Engine                                │
│  ├── High-fidelity tick-by-tick replay                      │
│  ├── Slippage & Fee modeling                                │
│  └── Performance Metrics (Sharpe, Drawdown, Win Rate)       │
└─────────────────────────────────────────────────────────────┘

Kết nối Tardis API - Bước đầu tiên

Để bắt đầu回测, bạn cần kết nối với Tardis để lấy dữ liệu lịch sử. Tardis cung cấp API RESTful với độ trễ thấp và dữ liệu được chuẩn hóa cho nhiều sàn giao dịch.

const axios = require('axios');

class TardisClient {
    constructor(apiKey) {
        this.baseUrl = 'https://api.tardis.dev/v1';
        this.apiKey = apiKey;
        this.headers = {
            'Authorization': Bearer ${this.apiKey},
            'Content-Type': 'application/json'
        };
    }

    // Lấy danh sách các sàn giao dịch được hỗ trợ
    async getExchanges() {
        const response = await axios.get(
            ${this.baseUrl}/exchanges,
            { headers: this.headers }
        );
        return response.data;
    }

    // Lấy danh sách symbols cho một sàn
    async getSymbols(exchange) {
        const response = await axios.get(
            ${this.baseUrl}/exchanges/${exchange}/symbols,
            { headers: this.headers }
        );
        return response.data;
    }

    // Lấy thông tin về dữ liệu có sẵn cho một symbol
    async getSymbolDetails(exchange, symbol) {
        const response = await axios.get(
            ${this.baseUrl}/exchanges/${exchange}/symbols/${symbol},
            { headers: this.headers }
        );
        return response.data;
    }

    // Tải historical L2 order book data
    async getHistoricalOrderBook(exchange, symbol, from, to) {
        const params = {
            from: Math.floor(new Date(from).getTime() / 1000),
            to: Math.floor(new Date(to).getTime() / 1000),
            format: 'json'
        };

        const response = await axios.get(
            ${this.baseUrl}/historical/${exchange}/${symbol}/orderbook-l2,
            { 
                headers: this.headers,
                params: params
            }
        );
        return response.data;
    }

    // Tải historical trades/recks
    async getHistoricalTrades(exchange, symbol, from, to) {
        const params = {
            from: Math.floor(new Date(from).getTime() / 1000),
            to: Math.floor(new Date(to).getTime() / 1000),
            format: 'json'
        };

        const response = await axios.get(
            ${this.baseUrl}/historical/${exchange}/${symbol}/trades,
            { 
                headers: this.headers,
                params: params
            }
        );
        return response.data;
    }
}

// Ví dụ sử dụng
const tardis = new TardisClient('YOUR_TARDIS_API_KEY');

async function main() {
    try {
        // Lấy danh sách sàn hỗ trợ
        const exchanges = await tardis.getExchanges();
        console.log('Sàn hỗ trợ:', exchanges.map(e => e.name));

        // Lấy symbols cho Binance
        const binanceSymbols = await tardis.getSymbols('binance');
        const btcSymbol = binanceSymbols.find(s => s.symbol.includes('BTC'));
        console.log('BTC Symbol:', btcSymbol);

        // Tải dữ liệu order book cho BTCUSDT
        const orderBookData = await tardis.getHistoricalOrderBook(
            'binance',
            'BTCUSDT',
            '2026-01-01T00:00:00Z',
            '2026-01-01T01:00:00Z'
        );
        console.log('Order Book Data Points:', orderBookData.length);
    } catch (error) {
        console.error('Lỗi khi kết nối Tardis:', error.message);
    }
}

main();

Xây dựng L2 Order Book Processor

Đây là phần core của hệ thống - xử lý raw L2 data và tính toán các chỉ báo micro-structure.

class L2OrderBookProcessor {
    constructor() {
        this.bids = new Map(); // price -> {qty, orders}
        this.asks = new Map();
        this.sequence = 0;
        this.trades = [];
        
        // Các ngưỡng cho phân tích
        this.thresholds = {
            imbalanceAlert: 0.3,     // OFI ngưỡng cảnh báo
            largeOrderThreshold: 5,  // Đơn vị BTC
            depthLevels: 10          // Số mức giá để phân tích
        };
    }

    // Cập nhật order book từ L2 snapshot
    updateFromSnapshot(snapshot) {
        const timestamp = snapshot.timestamp || Date.now();
        
        // Parse bids
        for (const [price, qty] of Object.entries(snapshot.bids || {})) {
            if (parseFloat(qty) === 0) {
                this.bids.delete(parseFloat(price));
            } else {
                this.bids.set(parseFloat(price), {
                    qty: parseFloat(qty),
                    timestamp: timestamp
                });
            }
        }

        // Parse asks
        for (const [price, qty] of Object.entries(snapshot.asks || {})) {
            if (parseFloat(qty) === 0) {
                this.asks.delete(parseFloat(price));
            } else {
                this.asks.set(parseFloat(price), {
                    qty: parseFloat(qty),
                    timestamp: timestamp
                });
            }
        }
    }

    // Cập nhật từ L2 update (delta)
    updateFromDelta(delta) {
        // Áp dụng các thay đổi
        for (const update of delta) {
            const { side, price, qty } = update;
            const book = side === 'buy' ? this.bids : this.asks;
            
            if (parseFloat(qty) === 0) {
                book.delete(parseFloat(price));
            } else {
                book.set(parseFloat(price), {
                    qty: parseFloat(qty),
                    timestamp: delta.timestamp
                });
            }
        }
        this.sequence = delta.sequence || this.sequence + 1;
    }

    // Tính Order Flow Imbalance (OFI)
    calculateOFI(windowMs = 1000) {
        const now = Date.now();
        const windowStart = now - windowMs;
        
        let bidVolumeChange = 0;
        let askVolumeChange = 0;

        // Lọc các thay đổi trong window
        for (const [price, data] of this.bids) {
            if (data.timestamp >= windowStart) {
                bidVolumeChange += data.qty;
            }
        }
        
        for (const [price, data] of this.asks) {
            if (data.timestamp >= windowStart) {
                askVolumeChange += data.qty;
            }
        }

        const totalVolume = bidVolumeChange + askVolumeChange;
        if (totalVolume === 0) return 0;
        
        // OFI = (Bid Change - Ask Change) / Total
        const ofi = (bidVolumeChange - askVolumeChange) / totalVolume;
        return Math.max(-1, Math.min(1, ofi)); // Normalize về [-1, 1]
    }

    // Tính micro VWAP
    calculateMicroVWAP(trades, windowMs = 5000) {
        const now = Date.now();
        const windowStart = now - windowMs;
        
        let totalVolume = 0;
        let volumeWeightedPrice = 0;
        
        for (const trade of trades) {
            if (trade.timestamp >= windowStart) {
                volumeWeightedPrice += trade.price * trade.qty;
                totalVolume += trade.qty;
            }
        }
        
        return totalVolume > 0 ? volumeWeightedPrice / totalVolume : null;
    }

    // Phát hiện vùng liquidity
    detectLiquidityZones(levels = 10) {
        const sortedBids = [...this.bids.entries()]
            .sort((a, b) => b[0] - a[0])
            .slice(0, levels);
            
        const sortedAsks = [...this.asks.entries()]
            .sort((a, b) => a[0] - b[0])
            .slice(0, levels);

        const midPrice = this.getMidPrice();
        
        return {
            bidZones: sortedBids.map(([price, data]) => ({
                price,
                qty: data.qty,
                distanceFromMid: ((midPrice - price) / midPrice * 100).toFixed(4) + '%'
            })),
            askZones: sortedAsks.map(([price, data]) => ({
                price,
                qty: data.qty,
                distanceFromMid: ((price - midPrice) / midPrice * 100).toFixed(4) + '%'
            })),
            midPrice
        };
    }

    // Phát hiện Iceberg Orders
    detectIcebergs() {
        const icebergCandidates = [];
        
        // Kiểm tra các lệnh lớn bất thường
        for (const [price, data] of this.bids) {
            if (data.qty >= this.thresholds.largeOrderThreshold) {
                // Tính tỷ lệ so với tổng bid depth
                const totalBidDepth = [...this.bids.values()]
                    .reduce((sum, d) => sum + d.qty, 0);
                const ratio = data.qty / totalBidDepth;
                
                if (ratio > 0.5) {
                    icebergCandidates.push({
                        side: 'buy',
                        price,
                        qty: data.qty,
                        ratio: (ratio * 100).toFixed(2) + '%',
                        type: ratio > 0.8 ? 'LARGE ICEBERG' : 'WHALE ORDER'
                    });
                }
            }
        }
        
        for (const [price, data] of this.asks) {
            if (data.qty >= this.thresholds.largeOrderThreshold) {
                const totalAskDepth = [...this.asks.values()]
                    .reduce((sum, d) => sum + d.qty, 0);
                const ratio = data.qty / totalAskDepth;
                
                if (ratio > 0.5) {
                    icebergCandidates.push({
                        side: 'sell',
                        price,
                        qty: data.qty,
                        ratio: (ratio * 100).toFixed(2) + '%',
                        type: ratio > 0.8 ? 'LARGE ICEBERG' : 'WHALE ORDER'
                    });
                }
            }
        }
        
        return icebergCandidates;
    }

    getMidPrice() {
        const bestBid = Math.max(...this.bids.keys());
        const bestAsk = Math.min(...this.asks.keys());
        return (bestBid + bestAsk) / 2;
    }

    getSpread() {
        const bestBid = Math.max(...this.bids.keys());
        const bestAsk = Math.min(...this.asks.keys());
        return {
            absolute: bestAsk - bestBid,
            percentage: ((bestAsk - bestBid) / this.getMidPrice() * 100).toFixed(4) + '%'
        };
    }

    // Lấy depth summary
    getDepthSummary() {
        const bidDepth = [...this.bids.values()]
            .reduce((sum, d) => sum + d.qty, 0);
        const askDepth = [...this.asks.values()]
            .reduce((sum, d) => sum + d.qty, 0);
        
        return {
            totalBidDepth: bidDepth,
            totalAskDepth: askDepth,
            imbalance: ((bidDepth - askDepth) / (bidDepth + askDepth)).toFixed(4),
            bidAskRatio: (bidDepth / askDepth).toFixed(4)
        };
    }
}

// Ví dụ sử dụng
const processor = new L2OrderBookProcessor();

// Giả lập dữ liệu L2
processor.updateFromSnapshot({
    timestamp: Date.now(),
    bids: {
        42150.50: 2.5,
        42150.00: 1.8,
        42149.50: 3.2,
        42149.00: 5.0,  // Whale order tiềm năng
        42148.50: 1.2
    },
    asks: {
        42151.00: 1.5,
        42151.50: 2.0,
        42152.00: 4.5,
        42152.50: 1.0,
        42153.00: 3.0
    }
});

console.log('=== Order Book Analysis ===');
console.log('Mid Price:', processor.getMidPrice());
console.log('Spread:', processor.getSpread());
console.log('Depth Summary:', processor.getDepthSummary());
console.log('Liquidity Zones:', processor.detectLiquidityZones());
console.log('Iceberg Detection:', processor.detectIcebergs());

Xây dựng Strategy Engine回测

Sau khi có L2 Processor, chúng ta xây dựng strategy engine để backtest các chiến lược giao dịch dựa trên micro-structure.

class MicroStructureStrategy {
    constructor(initialCapital = 10000) {
        this.capital = initialCapital;
        this.position = 0;
        this.trades = [];
        this.equityCurve = [];
        
        // Các tham số strategy
        this.params = {
            ofiThreshold: 0.25,      // Ngưỡng OFI để vào lệnh
            stopLoss: 0.002,         // 0.2% stop loss
            takeProfit: 0.005,       // 0.5% take profit
            positionSize: 0.1,      // 10% vốn mỗi lệnh
            reEntryDelay: 5000       // 5 giây chờ re-entry
        };
        
        // State tracking
        this.lastTradeTime = 0;
        this.currentOFI = 0;
        this.priceHistory = [];
    }

    // Cập nhật OFI
    updateOFI(ofi) {
        this.currentOFI = ofi;
    }

    // Cập nhật giá
    updatePrice(price, timestamp) {
        this.priceHistory.push({ price, timestamp });
        
        // Giữ chỉ 100 data points gần nhất
        if (this.priceHistory.length > 100) {
            this.priceHistory.shift();
        }
    }

    // Kiểm tra điều kiện vào lệnh
    checkEntryConditions(orderBookState) {
        const now = Date.now();
        
        // Kiểm tra re-entry delay
        if (now - this.lastTradeTime < this.params.reEntryDelay) {
            return { signal: 'NONE', reason: 'Re-entry delay' };
        }
        
        // Chiến lược 1: OFI Mean Reversion
        const ofiSignal = this.analyzeOFI();
        
        // Chiến lược 2: Order Book Imbalance
        const imbalanceSignal = this.analyzeImbalance(orderBookState);
        
        // Chiến lược 3: Break-out Detection
        const breakoutSignal = this.analyzeBreakout();
        
        // Tổng hợp tín hiệu
        let finalSignal = 'NONE';
        let confidence = 0;
        
        if (ofiSignal !== 'NONE') {
            confidence += ofiSignal === 'BUY' ? 1 : -1;
        }
        if (imbalanceSignal !== 'NONE') {
            confidence += imbalanceSignal === 'BUY' ? 1 : -1;
        }
        if (breakoutSignal !== 'NONE') {
            confidence += breakoutSignal === 'BUY' ? 1 : -1;
        }
        
        if (confidence >= 2) finalSignal = 'BUY';
        else if (confidence <= -2) finalSignal = 'SELL';
        
        return {
            signal: finalSignal,
            confidence,
            breakdown: { ofiSignal, imbalanceSignal, breakoutSignal }
        };
    }

    analyzeOFI() {
        // Mean reversion: OFI quá cao -> đảo chiều, OFI quá thấp -> đảo chiều
        if (this.currentOFI > this.params.ofiThreshold) {
            return 'SELL'; // Quá nhiều buy pressure -> có thể đảo
        } else if (this.currentOFI < -this.params.ofiThreshold) {
            return 'BUY';  // Quá nhiều sell pressure -> có thể đảo
        }
        return 'NONE';
    }

    analyzeImbalance(orderBookState) {
        const imbalance = parseFloat(orderBookState.imbalance);
        
        // Nếu bid depth >> ask depth -> có thể break-up
        if (imbalance > 0.3) {
            return 'BUY';
        } else if (imbalance < -0.3) {
            return 'SELL';
        }
        return 'NONE';
    }

    analyzeBreakout() {
        if (this.priceHistory.length < 20) return 'NONE';
        
        const recent = this.priceHistory.slice(-20);
        const prices = recent.map(p => p.price);
        
        const max = Math.max(...prices);
        const min = Math.min(...prices);
        const current = prices[prices.length - 1];
        const range = max - min;
        
        // Break-out upward: giá gần max với range lớn
        if (current > max - range * 0.1 && range / current > 0.001) {
            return 'BUY';
        }
        // Break-out downward
        if (current < min + range * 0.1 && range / current > 0.001) {
            return 'SELL';
        }
        
        return 'NONE';
    }

    // Thực hiện lệnh
    executeTrade(signal, price, timestamp) {
        if (signal === 'NONE' || this.position !== 0) {
            return null;
        }
        
        const positionValue = this.capital * this.params.positionSize;
        const qty = positionValue / price;
        const cost = qty * price;
        const fee = cost * 0.001; // 0.1% fee
        
        const trade = {
            side: signal,
            entryPrice: price,
            qty,
            cost,
            fee,
            timestamp,
            pnl: 0,
            exitPrice: null
        };
        
        if (signal === 'BUY') {
            this.position = qty;
        } else {
            this.position = -qty;
        }
        
        this.trades.push(trade);
        this.lastTradeTime = timestamp;
        
        return trade;
    }

    // Kiểm tra điều kiện thoát lệnh
    checkExitConditions(currentPrice, timestamp) {
        if (this.position === 0) return null;
        
        const lastTrade = this.trades[this.trades.length - 1];
        const pnlPercent = this.position > 0 
            ? (currentPrice - lastTrade.entryPrice) / lastTrade.entryPrice
            : (lastTrade.entryPrice - currentPrice) / lastTrade.entryPrice;
        
        // Stop loss
        if (pnlPercent <= -this.params.stopLoss) {
            return this.closeTrade(currentPrice, timestamp, 'STOP_LOSS');
        }
        
        // Take profit
        if (pnlPercent >= this.params.takeProfit) {
            return this.closeTrade(currentPrice, timestamp, 'TAKE_PROFIT');
        }
        
        return null;
    }

    closeTrade(price, timestamp, reason) {
        const lastTrade = this.trades[this.trades.length - 1];
        const pnl = this.position * price - this.position * lastTrade.entryPrice;
        const fee = Math.abs(this.position * price * 0.001);
        
        lastTrade.exitPrice = price;
        lastTrade.pnl = pnl - fee;
        lastTrade.exitReason = reason;
        
        this.capital += pnl - fee;
        this.position = 0;
        
        return lastTrade;
    }

    // Tính toán metrics hiệu suất
    calculatePerformance() {
        if (this.trades.length === 0) {
            return { message: 'Không có giao dịch nào được thực hiện' };
        }
        
        const closedTrades = this.trades.filter(t => t.exitPrice);
        
        const totalPnl = closedTrades.reduce((sum, t) => sum + t.pnl, 0);
        const winTrades = closedTrades.filter(t => t.pnl > 0);
        const loseTrades = closedTrades.filter(t => t.pnl <= 0);
        
        const avgWin = winTrades.length > 0 
            ? winTrades.reduce((sum, t) => sum + t.pnl, 0) / winTrades.length 
            : 0;
        const avgLoss = loseTrades.length > 0 
            ? Math.abs(loseTrades.reduce((sum, t) => sum + t.pnl, 0) / loseTrades.length) 
            : 0;
        
        const maxDrawdown = this.calculateMaxDrawdown();
        
        return {
            totalTrades: closedTrades.length,
            winRate: (winTrades.length / closedTrades.length * 100).toFixed(2) + '%',
            totalPnl: totalPnl.toFixed(2),
            avgWin: avgWin.toFixed(2),
            avgLoss: avgLoss.toFixed(2),
            profitFactor: avgLoss > 0 ? (avgWin * winTrades.length / (avgLoss * loseTrades.length)).toFixed(2) : '∞',
            maxDrawdown: maxDrawdown.toFixed(2),
            finalCapital: this.capital.toFixed(2),
            returnPercent: ((this.capital - 10000) / 10000 * 100).toFixed(2) + '%'
        };
    }

    calculateMaxDrawdown() {
        let peak = 10000;
        let maxDrawdown = 0;
        
        for (const trade of this.trades) {
            if (trade.pnl !== 0) {
                const equity = 10000 + trade.pnl;
                if (equity > peak) peak = equity;
                const drawdown = (peak - equity) / peak;
                if (drawdown > maxDrawdown) maxDrawdown = drawdown;
            }
        }
        
        return maxDrawdown * 100;
    }
}

// Ví dụ chạy backtest
const strategy = new MicroStructureStrategy(10000);

// Giả lập dữ liệu
const mockOrderBook = {
    imbalance: 0.35,
    totalBidDepth: 150,
    totalAskDepth: 100
};

strategy.updatePrice(42150.00, Date.now());
strategy.updateOFI(0.28);

const entrySignal = strategy.checkEntryConditions(mockOrderBook);
console.log('Entry Signal:', entrySignal);

if (entrySignal.signal !== 'NONE') {
    const trade = strategy.executeTrade(entrySignal.signal, 42150.00, Date.now());
    console.log('Trade Executed:', trade);
}

Backtest Engine hoàn chỉnh

Giờ chúng ta kết hợp tất cả lại thành một backtest engine hoàn chỉnh, xử lý dữ liệu thực từ Tardis.

class TardisBacktestEngine {
    constructor(config = {}) {
        this.tardis = new TardisClient(config.tardisApiKey);
        this.orderBookProcessor = new L2OrderBookProcessor();
        this.strategy = new MicroStructureStrategy(config.initialCapital || 10000);
        
        // Cấu hình
        this.config = {
            exchange: config.exchange || 'binance',
            symbol: config.symbol || 'BTCUSDT',
            startDate: config.startDate,
            endDate: config.endDate,
            ...config
        };
        
        // Metrics
        this.metrics = {
            ticksProcessed: 0,
            latency: [],
            errors: []
        };
    }

    async loadHistoricalData() {
        console.log(Đang tải dữ liệu từ ${this.config.startDate} đến ${this.config.endDate}...);
        
        try {
            const [orderBookData, tradesData] = await Promise.all([
                this.tardis.getHistoricalOrderBook(
                    this.config.exchange,
                    this.config.symbol,
                    this.config.startDate,
                    this.config.endDate
                ),
                this.tardis.getHistoricalTrades(
                    this.config.exchange,
                    this.config.symbol,
                    this.config.startDate,
                    this.config.endDate
                )
            ]);
            
            console.log(Đã tải ${orderBookData.length} order book updates);
            console.log(Đã tải ${tradesData.length} trades);
            
            return { orderBookData, tradesData };
        } catch (error) {
            console.error('Lỗi khi tải dữ liệu:', error.message);
            throw error;
        }
    }

    async runBacktest(onProgress) {
        const { orderBookData, tradesData } = await this.loadHistoricalData();
        
        // Sort theo timestamp
        orderBookData.sort((a, b) => a.timestamp - b.timestamp);
        tradesData.sort((a, b) => a.timestamp - b.timestamp);
        
        const totalTicks = orderBookData.length;
        let tradeIndex = 0;
        
        console.log(Bắt đầu backtest với ${totalTicks} ticks...);
        
        for (let i = 0; i < totalTicks; i++) {
            const tick = orderBookData[i];
            const startTime = Date.now();
            
            try {
                // Cập nhật order book
                if (tick.type === 'snapshot') {
                    this.orderBookProcessor.updateFromSnapshot(tick);
                } else {
                    this.orderBookProcessor.updateFromDelta(tick);
                }
                
                // Cập nhật OFI
                const ofi = this.orderBookProcessor.calculateOFI();
                this.strategy.updateOFI(ofi);
                
                // Cập nhật giá từ trades gần nhất
                while (tradeIndex < tradesData.length && 
                       tradesData[tradeIndex].timestamp <= tick.timestamp) {
                    const trade = tradesData[tradeIndex];
                    this.strategy.updatePrice(trade.price, trade.timestamp);
                    
                    // Kiểm tra exit conditions
                    const exitTrade = this.strategy.checkExitConditions(
                        trade.price, 
                        trade.timestamp
                    );
                    
                    if (exitTrade) {
                        console.log(EXIT: ${exitTrade.exitReason} @ ${exitTrade.exitPrice});
                    }
                    
                    tradeIndex++;
                }
                
                // Kiểm tra entry conditions (mỗi 100 ticks để tiết kiệm compute)
                if (i % 100 === 0) {
                    const orderBookState = this.orderBookProcessor.getDepthSummary();
                    const signal = this.strategy.checkEntryConditions(orderBookState);
                    
                    if (signal.signal !== 'NONE') {
                        const lastPrice = this.strategy.priceHistory.slice(-1)[0]?.price;
                        if (lastPrice) {
                            const trade = this.strategy.executeTrade(
                                signal.signal, 
                                lastPrice, 
                                tick.timestamp
                            );
                            if (trade) {
                                console.log(ENTRY: ${signal.signal} @ ${trade.entryPrice});
                            }
                        }
                    }
                }
                
                this.metrics.ticksProcessed++;
                
                // Progress reporting
                if (onProgress && i % 1000 === 0) {
                    const progress = ((i / totalTicks) * 100).toFixed(1);
                    onProgress({
                        progress,
                        ticksProcessed: this.metrics.ticksProcessed,
                        capital: this.strategy.capital.toFixed(2)
                    });
                }
                
            } catch (error) {
                this.metrics.errors.push({
                    timestamp: tick.timestamp,
                    error: error.message
                });
            }
            
            // Track latency
            const latency = Date.now() - startTime;
            this.metrics.latency.push(latency);
        }
        
        return this.generateReport();
    }

    generateReport() {
        const performance = this.strategy.calculatePerformance();
        const avgLatency = this.metrics.latency.reduce((a, b) => a + b, 0) / 
                          this.metrics.latency.length;
        const maxLatency = Math.max(...this.metrics.latency);
        
        return {
            performance,
            dataQuality: {
                ticksProcessed: this.metrics.ticksProcessed,
                errors: this.metrics.errors.length,
                errorRate: (this.metrics.errors.length / this.metrics.ticksProcessed * 100).toFixed(4) + '%'
            },
            processingSpeed: {
                avgLatencyMs: avgLatency.toFixed(2),
                maxLatencyMs: maxLatency,
                totalTimeMs: this.metrics.latency.reduce((a, b) => a + b, 0)
            },
            config: this.config
        };
    }

    // Xuất kết quả ra file
    exportResults(report, filename = 'backtest_report.json') {
        const fs = require('fs');
        fs.writeFileSync(filename, JSON.stringify(report, null, 2));
        console.log(Đã lưu report vào ${filename});
    }
}

// Chạy backtest
async function main() {
    const engine = new TardisBacktestEngine({
        tardisApiKey: 'YOUR_TARDIS_API_KEY',
        exchange: 'binance',
        symbol: 'BTCUSDT',
        startDate: '2026-01-15T00:00:00Z',
        endDate: '2026-01-16T00:00:00Z',
        initialCapital: 10000
    });

    try {
        const report = await engine.runBacktest((progress) => {
            console.log(Tiến trình: ${progress.progress}% | Vốn: $${progress.capital});
        });
        
        console.log('\n=== BACKTEST REPORT ===');
        console.log(JSON.stringify(report.performance, null, 2));
        
        // Lưu report
        engine.exportResults(report);
        
    } catch (error) {
        console.error('Backtest failed:', error);
    }
}

main();

So sánh AI API cho phân tích dữ liệu回测

Trong quá trình xây dựng và tối ưu chiến lược, bạn có thể sử dụng AI để phân tích kết quả, generate code, và debug. Dưới đây là bảng so sánh chi phí thực tế:

Model Giá/MTok Chi phí 10M tokens/tháng Độ trễ trung bình Phù hợp cho
DeepSeek V3.2 $0.42 $4,200 ~45ms Code generation, optimization
Gemini 2.5 Flash $2.50 $25,000

🔥 Thử HolySheep AI

Cổng AI API trực tiếp. Hỗ trợ Claude, GPT-5, Gemini, DeepSeek — một khóa, không cần VPN.

👉 Đăng ký miễn phí →