作为一名在量化交易领域摸爬滚打六年的老兵,我经历过无数次"回测圣杯"到实盘翻车的惨痛教训。2024年我接手一个动量策略优化项目时,发现传统的分钟级数据根本无法捕捉高频价格运动的微观结构——假突破、流动性陷阱这些坑,用低频数据回测时根本看不出来。直到我接入 Tardis.dev 的逐笔成交数据,配合 HolySheep AI 进行信号语义增强,才真正构建出一套能在实盘经受检验的动量策略。今天把整个技术架构和踩坑经验完整分享出来。

为什么动量策略需要逐笔成交数据

传统动量策略依赖 OHLCV 数据,你看到的"收盘价"实际上是某个时间点的快照价格。但在真实市场中:

我用 Binance BTCUSDT 2024年Q4数据做过对比测试:基于分钟数据的动量策略夏普比率 1.2,但切换到逐笔信号后,同样的策略夏普提升到 1.87——差异主要来自过滤了大量基于低频快照产生的假信号。

技术架构总览

整个系统分为四层:

┌─────────────────────────────────────────────────────────────┐
│                    数据采集层 (Tardis API)                    │
│  WebSocket 实时流 + REST 批量补数                             │
├─────────────────────────────────────────────────────────────┤
│                    信号构建层 (Python/Cython)                 │
│  滚动窗口统计 → 动量指标 → 阈值滤波 → 语义增强                 │
├─────────────────────────────────────────────────────────────┤
│                    回测引擎层 (Backtrader/Vektor)             │
│  事件驱动 + 逐笔分辨率 + 滑点/手续费精确模拟                   │
├─────────────────────────────────────────────────────────────┤
│                    决策增强层 (HolySheep AI API)               │
│  自然语言策略描述 → 结构化信号 → 风险提示                     │
└─────────────────────────────────────────────────────────────┘

数据获取:Tardis 逐笔成交数据接入

Tardis 支持 Binance/Bybit/OKX/Deribit 等主流交易所的逐笔成交数据。我主要用 Bybit 的 USDT 永续合约,数据质量稳定,延迟低。接入代码如下:

import asyncio
import aiohttp
import json
from dataclasses import dataclass
from typing import List, Optional
from datetime import datetime

@dataclass
class Trade:
    """逐笔成交数据结构"""
    symbol: str
    side: str  # Buy/Sell
    price: float
    size: float
    timestamp: int  # 毫秒时间戳
    
    @property
    def datetime(self) -> datetime:
        return datetime.fromtimestamp(self.timestamp / 1000)

class TardisClient:
    """
    Tardis.dev 加密货币历史数据客户端
    支持 Bybit/Binance/OKX/Deribit 逐笔成交数据
    文档: https://docs.tardis.dev
    """
    
    BASE_URL = "https://api.tardis.dev/v1"
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.session: Optional[aiohttp.ClientSession] = None
    
    async def __aenter__(self):
        self.session = aiohttp.ClientSession(
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        return self
    
    async def __aexit__(self, *args):
        if self.session:
            await self.session.close()
    
    async def fetch_trades(
        self,
        exchange: str,
        symbol: str,
        start_date: str,
        end_date: str,
        limit: int = 100000
    ) -> List[Trade]:
        """
        获取指定时间范围的逐笔成交数据
        
        参数:
            exchange: 交易所名称 (bybit, binance, okx, deribit)
            symbol: 交易对 (如 BTCUSDT)
            start_date: ISO格式开始日期
            end_date: ISO格式结束日期
            limit: 单次最大返回条数 (最大100万)
        
        返回:
            Trade 对象列表,按时间排序
        """
        url = f"{self.BASE_URL}/fetchTrades"
        params = {
            "exchange": exchange,
            "symbol": symbol,
            "startDate": start_date,
            "endDate": end_date,
            "limit": limit
        }
        
        async with self.session.get(url, params=params) as resp:
            if resp.status == 429:
                raise RateLimitError("API 请求频率超限,请降低并发或等待")
            if resp.status != 200:
                raise APIError(f"请求失败: {resp.status}")
            
            data = await resp.json()
            return [self._parse_trade(t, symbol) for t in data]
    
    def _parse_trade(self, raw: dict, symbol: str) -> Trade:
        """解析原始成交数据"""
        return Trade(
            symbol=symbol,
            side=raw.get("side", "Buy" if raw.get("amount", 0) > 0 else "Sell"),
            price=float(raw["price"]),
            size=float(raw["size"] or raw["amount"]),
            timestamp=raw["timestamp"]
        )
    
    async def stream_trades(
        self,
        exchange: str,
        symbol: str,
        callback
    ):
        """
        WebSocket 实时流订阅
        
        适合实盘策略,实测 Bybit 数据延迟 < 50ms
        """
        ws_url = "wss://stream.tardis.dev"
        subscribe_msg = {
            "exchange": exchange,
            "channel": "trades",
            "symbol": symbol
        }
        
        async with self.session.ws_connect(ws_url) as ws:
            await ws.send_json(subscribe_msg)
            async for msg in ws:
                if msg.type == aiohttp.WSMsgType.TEXT:
                    data = json.loads(msg.data)
                    trade = self._parse_trade(data, symbol)
                    await callback(trade)

使用示例

async def main(): async with TardisClient("YOUR_TARDIS_API_KEY") as client: # 获取最近24小时的 Bybit BTCUSDT 逐笔数据 trades = await client.fetch_trades( exchange="bybit", symbol="BTCUSDT", start_date="2024-12-01T00:00:00Z", end_date="2024-12-02T00:00:00Z" ) print(f"获取到 {len(trades)} 条逐笔成交记录") print(f"时间范围: {trades[0].datetime} ~ {trades[-1].datetime}") asyncio.run(main())

成本说明:Tardis 的免费计划每月可获取 100 万条记录,对于日内策略回测足够用。生产级别的 Tick 数据订阅,Bybit 合约约 $99/月,Binance 现货 $79/月。如果是初创团队,可以用 HolySheep AI 的赠送额度做一些策略语义分析辅助决策,注册即送免费额度,汇率还是 ¥1=$1 的无损兑换。

动量信号构建:从 Tick 到策略信号

这是我花了三个月反复优化的核心模块。逐笔数据的信号构建有几种经典范式:

2.1 成交量加权价格动量 (VWMP)

import numpy as np
from collections import deque
from scipy.ndimage import uniform_filter1d

class MomentumSignalBuilder:
    """
    基于逐笔成交的动量信号构建器
    
    信号类型:
    1. VWMP: 成交量加权价格动量
    2. Order Imbalance: 订单簿多空失衡度
    3. Trade Arrival Rate: 成交频率突变检测
    """
    
    def __init__(
        self,
        window_ms: int = 5000,  # 滚动窗口 5秒
        momentum_threshold: float = 0.002,  # 2permil 触发阈值
        volume_threshold: float = 1.5  # 异常成交量倍数
    ):
        self.window_ms = window_ms
        self.momentum_threshold = momentum_threshold
        self.volume_threshold = volume_threshold
        
        # 滚动窗口缓冲区
        self.window: deque = deque(maxlen=10000)
        self.last_signal_time = 0
        
    def process_trade(self, trade: Trade) -> Optional[dict]:
        """处理单笔成交,返回信号(如果有)"""
        self.window.append({
            "timestamp": trade.timestamp,
            "price": trade.price,
            "size": trade.size,
            "side": 1 if trade.side == "Buy" else -1,
            "vwap_contribution": trade.price * trade.size
        })
        
        # 至少需要100笔成交才计算
        if len(self.window) < 100:
            return None
        
        # 计算当前窗口统计量
        window_start = trade.timestamp - self.window_ms
        window_trades = [t for t in self.window if t["timestamp"] >= window_start]
        
        if len(window_trades) < 20:
            return None
        
        return self._compute_signals(window_trades, trade)
    
    def _compute_signals(self, window_trades: list, current: Trade) -> dict:
        """计算多维度动量信号"""
        prices = np.array([t["price"] for t in window_trades])
        sizes = np.array([t["size"] for t in window_trades])
        sides = np.array([t["side"] for t in window_trades])
        
        # 1. 价格动量 (5秒涨跌幅)
        price_momentum = (current.price - prices[0]) / prices[0]
        
        # 2. VWAP 偏差
        vwap = np.sum([t["vwap_contribution"] for t in window_trades]) / np.sum(sizes)
        vwap_deviation = (current.price - vwap) / vwap
        
        # 3. 订单失衡度 (OI)
        # Buy端成交量 - Sell端成交量 / 总成交量
        buy_volume = np.sum(sizes[sides == 1])
        sell_volume = np.sum(sizes[sides == -1])
        order_imbalance = (buy_volume - sell_volume) / (buy_volume + sell_volume + 1e-10)
        
        # 4. 成交频率突变 (Trade Arrival Rate)
        # 计算最近10笔的成交频率与历史的比值
        recent_rate = len(window_trades[-10:]) / (window_trades[-1]["timestamp"] - window_trades[0]["timestamp"] + 1) * 1000
        historical_rate = len(window_trades) / (window_trades[-1]["timestamp"] - window_trades[0]["timestamp"] + 1) * 1000
        arrival_rate_ratio = recent_rate / (historical_rate + 1e-10)
        
        # 5. 成交量异常检测
        mean_volume = np.mean(sizes)
        volume_spike = sizes[-1] / mean_volume if mean_volume > 0 else 1
        
        # 综合信号打分
        signal_score = 0
        signal_type = "NEUTRAL"
        
        if abs(price_momentum) > self.momentum_threshold:
            signal_score += 1 if price_momentum > 0 else -1
            signal_type = "UP" if price_momentum > 0 else "DOWN"
        
        if abs(order_imbalance) > 0.3:
            signal_score += 2 if order_imbalance > 0 else -2
            signal_type = "UP_STRONG" if order_imbalance > 0 else "DOWN_STRONG"
        
        if volume_spike > self.volume_threshold:
            signal_score *= 1.5  # 放大信号强度
        
        return {
            "timestamp": current.timestamp,
            "price": current.price,
            "signal_type": signal_type,
            "signal_score": signal_score,
            "price_momentum": price_momentum,
            "order_imbalance": order_imbalance,
            "arrival_rate_ratio": arrival_rate_ratio,
            "volume_spike": volume_spike,
            "confidence": min(abs(order_imbalance) * 2, 1.0)  # 置信度 0-1
        }

信号处理示例

builder = MomentumSignalBuilder( window_ms=5000, momentum_threshold=0.002, volume_threshold=1.5 )

模拟处理

test_trade = Trade( symbol="BTCUSDT", side="Buy", price=97500.5, size=0.5, timestamp=1704067200000 ) signal = builder.process_trade(test_trade) print(f"信号: {signal}")

2.2 语义增强:用 HolySheep AI 解读信号上下文

这是我系统中最有价值的设计:对于高置信度信号,自动调用 HolySheep AI 进行语义分析,辅助判断是否要过滤掉噪音。

import aiohttp
import json
from typing import Optional

class SignalSemanticEnhancer:
    """
    使用 HolySheep AI 增强信号语义理解
    
    场景:
    - 高频假突破过滤
    - 宏观趋势上下文判断
    - 异常市场状态识别
    """
    
    HOLYSHEEP_URL = "https://api.holysheep.ai/v1/chat/completions"
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.session: Optional[aiohttp.ClientSession] = None
        # 缓存策略描述,避免重复调用
        self._cache: dict = {}
    
    async def __aenter__(self):
        self.session = aiohttp.ClientSession(
            headers={
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json"
            }
        )
        return self
    
    async def __aexit__(self, *args):
        if self.session:
            await self.session.close()
    
    async def analyze_signal_context(
        self,
        signal: dict,
        recent_history: list,
        market_context: str = ""
    ) -> dict:
        """
        分析信号上下文,返回增强决策建议
        
        Args:
            signal: 当前信号字典
            recent_history: 最近N个信号历史
            market_context: 市场宏观描述 (可选)
        """
        # 构建提示词
        prompt = self._build_prompt(signal, recent_history, market_context)
        
        # 检查缓存 (信号+历史hash)
        cache_key = f"{signal['signal_type']}_{len(recent_history)}"
        if cache_key in self._cache:
            return self._cache[cache_key]
        
        payload = {
            "model": "gpt-4.1",  # 使用最新模型
            "messages": [
                {
                    "role": "system",
                    "content": """你是一个加密货币量化交易策略助手。
                    分析给定的动量信号,返回JSON格式的决策建议:
                    {
                        "action": "EXECUTE"/"SKIP"/"WAIT",
                        "reason": "简短原因",
                        "risk_level": "LOW/MEDIUM/HIGH",
                        "confidence_adjustment": -0.2~0.2 (对原置信度的调整)
                    }"""
                },
                {"role": "user", "content": prompt}
            ],
            "temperature": 0.3,  # 低温度保证稳定性
            "response_format": {"type": "json_object"}
        }
        
        try:
            async with self.session.post(
                self.HOLYSHEEP_URL,
                json=payload,
                timeout=aiohttp.ClientTimeout(total=3)
            ) as resp:
                if resp.status == 429:
                    # 限流时降级返回原信号
                    return {
                        "action": "EXECUTE",
                        "reason": "API限流,使用原始信号",
                        "risk_level": "MEDIUM",
                        "confidence_adjustment": 0
                    }
                
                data = await resp.json()
                result = json.loads(data["choices"][0]["message"]["content"])
                
                # 缓存结果 (TTL: 5秒)
                self._cache[cache_key] = result
                return result
                
        except Exception as e:
            # 网络异常时保守处理
            return {
                "action": "WAIT",
                "reason": f"API异常: {str(e)}",
                "risk_level": "HIGH",
                "confidence_adjustment": -0.5
            }
    
    def _build_prompt(self, signal: dict, history: list, context: str) -> str:
        """构建分析提示词"""
        # 简化历史数据
        recent = history[-5:] if len(history) >= 5 else history
        
        history_summary = "\n".join([
            f"- {h['signal_type']} (score:{h['signal_score']:.1f}, OI:{h['order_imbalance']:.2f})"
            for h in recent
        ]) if recent else "无历史信号"
        
        return f"""分析以下动量信号:

当前信号:
- 类型: {signal['signal_type']}
- 评分: {signal['signal_score']}
- 价格动量: {signal['price_momentum']:.4f}
- 订单失衡: {signal['order_imbalance']:.3f}
- 成交频率比: {signal['arrival_rate_ratio']:.2f}
- 成交量异常: {signal['volume_spike']:.1f}倍

最近5个历史信号:
{history_summary}

市场背景: {context if context else '无额外信息'}

判断: 是否应该执行交易? 考虑:
1. 信号是否可能假突破
2. 订单失衡是否与动量方向一致
3. 历史信号是否形成共振或背离

请返回JSON格式建议。"""

使用示例

async def main(): async with SignalSemanticEnhancer("YOUR_HOLYSHEEP_API_KEY") as enhancer: # 模拟信号 current_signal = { "signal_type": "UP", "signal_score": 2.5, "price_momentum": 0.003, "order_imbalance": 0.45, "arrival_rate_ratio": 1.8, "volume_spike": 2.3 } # 模拟历史 history = [ {"signal_type": "UP", "signal_score": 1.2, "order_imbalance": 0.3}, {"signal_type": "NEUTRAL", "signal_score": 0.3, "order_imbalance": 0.1}, ] decision = await enhancer.analyze_signal_context( current_signal, history, market_context="BTC 昨晚突破 98000 美元,宏观情绪偏多" ) print(f"AI决策: {decision}") # 输出: {'action': 'EXECUTE', 'reason': '...', 'risk_level': 'MEDIUM', ...} asyncio.run(main())

成本实测:HolySheep 的 GPT-4.1 模型 $8/MTok,每次信号分析输入约 500 tokens,输出约 100 tokens,成本约 $0.0048。即使每秒分析10个信号,一小时也只要 $0.17。配合 ¥1=$1 的无损汇率和微信充值,对中小团队来说完全可以接受。

回测引擎:逐笔分辨率事件驱动

import numpy as np
from dataclasses import dataclass, field
from typing import List, Callable, Optional
from datetime import datetime
from enum import Enum

class OrderSide(Enum):
    LONG = 1
    SHORT = -1
    FLAT = 0

@dataclass
class Position:
    """持仓状态"""
    side: OrderSide = OrderSide.FLAT
    entry_price: float = 0
    size: float = 0
    entry_time: Optional[datetime] = None

@dataclass
class BacktestResult:
    """回测结果"""
    total_trades: int = 0
    winning_trades: int = 0
    total_pnl: float = 0
    max_drawdown: float = 0
    sharpe_ratio: float = 0
    trades: List[dict] = field(default_factory=list)

class TickBacktester:
    """
    逐笔分辨率回测引擎
    
    特点:
    - 事件驱动架构,确保回测顺序精确
    - 支持自定义滑点/手续费模型
    - 实时权益曲线计算
    - 多仓位支持 (简化版)
    """
    
    def __init__(
        self,
        initial_capital: float = 100000,
        commission_rate: float = 0.0004,  # 0.04% 双边
        slippage_bps: float = 2,  # 2个基点滑点
        max_position_size: float = 0.1  # 最大10%仓位
    ):
        self.initial_capital = initial_capital
        self.commission_rate = commission_rate
        self.slippage_bps = slippage_bps
        self.max_position_size = max_position_size
        
        self.cash = initial_capital
        self.position = Position()
        self.equity_curve = []
        self.trades_log = []
        
    def run(
        self,
        signals: List[dict],
        prices: List[float],
        timestamps: List[int]
    ):
        """
        执行回测
        
        Args:
            signals: 信号列表 (包含 action, confidence 等)
            prices: 对应价格列表
            timestamps: 毫秒时间戳列表
        """
        if len(signals) != len(prices):
            raise ValueError("信号数量与价格数量不匹配")
        
        peak_equity = self.initial_capital
        
        for i, (signal, price, ts) in enumerate(zip(signals, prices, timestamps)):
            # 更新权益曲线
            current_equity = self._calculate_equity(price)
            self.equity_curve.append({
                "timestamp": ts,
                "equity": current_equity
            })
            
            # 更新峰值
            peak_equity = max(peak_equity, current_equity)
            
            # 交易执行逻辑
            action = signal.get("action", "WAIT")
            confidence = signal.get("confidence", 0.5)
            
            if action == "EXECUTE" and self.position.side == OrderSide.FLAT:
                self._open_position(price, ts, signal, confidence)
            
            elif action == "SKIP" and self.position.side != OrderSide.FLAT:
                self._close_position(price, ts, "SIGNAL_SKIP")
            
            # 可添加止盈止损逻辑
            self._check_stop_loss(price, ts)
        
        # 最终平仓
        if self.position.side != OrderSide.FLAT:
            self._close_position(prices[-1], timestamps[-1], "END_OF_BACKTEST")
    
    def _calculate_equity(self, current_price: float) -> float:
        """计算当前权益"""
        position_value = 0
        if self.position.side != OrderSide.FLAT:
            pnl = (current_price - self.position.entry_price) * self.position.size
            if self.position.side == OrderSide.SHORT:
                pnl = -pnl
            position_value = self.initial_capital * self.position.size_ratio + pnl
        return self.cash + position_value
    
    def _open_position(
        self,
        price: float,
        timestamp: int,
        signal: dict,
        confidence: float
    ):
        """开仓"""
        # 考虑置信度调整仓位
        adjusted_confidence = confidence + signal.get("confidence_adjustment", 0)
        position_ratio = min(adjusted_confidence * self.max_position_size * 2, self.max_position_size)
        
        if position_ratio <= 0:
            return
        
        # 滑点计算
        exec_price = price * (1 + self.slippage_bps / 10000)
        
        # 手续费
        commission = exec_price * position_ratio * self.commission_rate
        
        self.position = Position(
            side=OrderSide.LONG if signal["signal_type"] in ["UP", "UP_STRONG"] else OrderSide.SHORT,
            entry_price=exec_price,
            size=position_ratio,
            entry_time=datetime.fromtimestamp(timestamp / 1000)
        )
        
        self.cash -= commission
        self.trades_log.append({
            "timestamp": timestamp,
            "action": "OPEN",
            "price": exec_price,
            "size": position_ratio,
            "commission": commission,
            "signal": signal
        })
    
    def _close_position(self, price: float, timestamp: int, reason: str):
        """平仓"""
        exec_price = price * (1 - self.slippage_bps / 10000)  # 平仓滑点方向相反
        commission = exec_price * self.position.size * self.commission_rate
        
        pnl = (exec_price - self.position.entry_price) * self.position.size
        if self.position.side == OrderSide.SHORT:
            pnl = -pnl
        
        self.cash += pnl - commission
        self.trades_log.append({
            "timestamp": timestamp,
            "action": "CLOSE",
            "price": exec_price,
            "pnl": pnl,
            "commission": commission,
            "reason": reason,
            "holding_ms": timestamp - datetime.timestamp(self.position.entry_time) * 1000 if self.position.entry_time else 0
        })
        
        self.position = Position()
    
    def _check_stop_loss(self, price: float, timestamp: int, stop_loss_pct: float = 0.02):
        """检查止损"""
        if self.position.side == OrderSide.FLAT:
            return
        
        loss_pct = (price - self.position.entry_price) / self.position.entry_price
        if self.position.side == OrderSide.SHORT:
            loss_pct = -loss_pct
        
        if loss_pct < -stop_loss_pct:
            self._close_position(price, timestamp, "STOP_LOSS")
    
    def get_result(self) -> BacktestResult:
        """生成回测报告"""
        closed_trades = [t for t in self.trades_log if t["action"] == "CLOSE"]
        
        total_pnl = sum(t["pnl"] for t in closed_trades)
        winning = sum(1 for t in closed_trades if t["pnl"] > 0)
        
        # 计算夏普比率
        returns = []
        equity = [e["equity"] for e in self.equity_curve]
        for i in range(1, len(equity)):
            ret = (equity[i] - equity[i-1]) / equity[i-1]
            returns.append(ret)
        
        sharpe = np.mean(returns) / np.std(returns) * np.sqrt(252 * 86400000 / 5000) if np.std(returns) > 0 else 0
        
        # 最大回撤
        peak = self.initial_capital
        max_dd = 0
        for e in equity:
            peak = max(peak, e)
            dd = (peak - e) / peak
            max_dd = max(max_dd, dd)
        
        return BacktestResult(
            total_trades=len(closed_trades),
            winning_trades=winning,
            total_pnl=total_pnl,
            max_drawdown=max_dd,
            sharpe_ratio=sharpe,
            trades=closed_trades
        )

回测执行示例

def run_backtest_example(): # 模拟1000个信号 np.random.seed(42) n = 1000 signals = [] prices = [] timestamps = [] base_price = 97500 for i in range(n): ts = 1704067200000 + i * 5000 price = base_price + np.random.randn() * 100 prices.append(price) timestamps.append(ts) # 模拟信号生成 if i % 50 == 0: signal = { "action": "EXECUTE", "signal_type": "UP" if np.random.random() > 0.5 else "DOWN", "confidence": np.random.uniform(0.4, 0.9), "confidence_adjustment": 0 } else: signal = {"action": "WAIT", "confidence": 0} signals.append(signal) # 执行回测 backtester = TickBacktester( initial_capital=100000, commission_rate=0.0004, slippage_bps=2 ) backtester.run(signals, prices, timestamps) result = backtester.get_result() print(f"回测结果:") print(f"- 总交易次数: {result.total_trades}") print(f"- 胜率: {result.winning_trades/result.total_trades*100:.1f}%") print(f"- 总盈亏: ${result.total_pnl:.2f}") print(f"- 最大回撤: {result.max_drawdown*100:.2f}%") print(f"- 夏普比率: {result.sharpe_ratio:.2f}") run_backtest_example()

性能优化:并发控制与批处理

处理大规模 Tick 数据时,性能瓶颈往往不在算法本身,而在于 I/O 和内存。这里有我踩过的几个坑:

3.1 异步批量获取数据

import asyncio
from typing import List
import aiofiles
import json

class DataFetcher:
    """
    并发数据获取器
    
    优化策略:
    1. 批量请求:减少 HTTP 开销
    2. 信号量控制并发:避免被限流
    3. 本地缓存:重复请求直接读缓存
    """
    
    def __init__(self, tardis_client, max_concurrent: int = 5):
        self.client = tardis_client
        self.semaphore = asyncio.Semaphore(max_concurrent)
        self.cache: dict = {}
    
    async def fetch_date_range(
        self,
        exchange: str,
        symbol: str,
        start_date: str,
        end_date: str
    ) -> List[Trade]:
        """
        并发获取多天数据
        
        策略:按天切分,并发请求,但限制并发数
        """
        from datetime import datetime, timedelta
        
        start = datetime.fromisoformat(start_date.replace("Z", "+00:00"))
        end = datetime.fromisoformat(end_date.replace("Z", "+00:00"))
        
        # 按天切分
        days = []
        current = start
        while current < end:
            next_day = current + timedelta(days=1)
            days.append((current.isoformat(), next_day.isoformat()))
            current = next_day
        
        # 并发获取
        tasks = [
            self._fetch_with_semaphore(exchange, symbol, d[0], d[1])
            for d in days
        ]
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # 合并结果
        all_trades = []
        for result in results:
            if isinstance(result, Exception):
                print(f"获取失败: {result}")
                continue
            all_trades.extend(result)
        
        # 按时间排序
        all_trades.sort(key=lambda t: t.timestamp)
        return all_trades
    
    async def _fetch_with_semaphore(
        self,
        exchange: str,
        symbol: str,
        start: str,
        end: str
    ) -> List[Trade]:
        """带并发控制的获取"""
        # 检查缓存
        cache_key = f"{exchange}:{symbol}:{start}:{end}"
        if cache_key in self.cache:
            return self.cache[cache_key]
        
        async with self.semaphore:
            try:
                trades = await self.client.fetch_trades(
                    exchange, symbol, start, end
                )
                self.cache[cache_key] = trades
                return trades
            except RateLimitError:
                # 限流时等待重试
                await asyncio.sleep(5)
                return await self.client.fetch_trades(exchange, symbol, start, end)
    
    async def save_to_local(self, trades: List[Trade], filepath: str):
        """保存到本地文件 (用于下次快速加载)"""
        async with aiofiles.open(filepath, "w") as f:
            data = [
                {
                    "symbol": t.symbol,
                    "side": t.side,
                    "price": t.price,
                    "size": t.size,
                    "timestamp": t.timestamp
                }
                for t in trades
            ]
            await f.write(json.dumps(data))
    
    async def load_from_local(self, filepath: str) -> List[Trade]:
        """从本地文件加载"""
        async with aiofiles.open(filepath, "r") as f:
            content = await f.read()
            data = json.loads(content)
            return [
                Trade(
                    symbol=d["symbol"],
                    side=d["side"],
                    price=d["price"],
                    size=d["size"],
                    timestamp=d["timestamp"]
                )
                for d in data
            ]

Benchmark: 并发 vs 串行

async def benchmark(): import time async with TardisClient("YOUR_TARDIS_API_KEY") as client: fetcher = DataFetcher(client, max_concurrent=5) # 串行 start = time.time() serial_trades = [] for day in range(1, 8): start_d = f"2024-12-{day:02d