回测是量化交易策略开发中最关键的环节之一。作为一名有7年量化开发经验的工程师,我踩过无数坑:从数据延迟、内存溢出到回测结果与实盘严重背离。今天我将分享如何使用Tardis API获取OKX永续合约的Tick级数据,并构建生产级回测系统。文中所有代码均经过实盘验证,可直接复制使用。
为什么选择Tardis API + OKX永续合约
在做高频策略回测时,数据质量决定了策略的生死。我测试过多家数据供应商:
- Binance: 需要自己维护WebSocket连接,数据清洗工作量巨大
- CCXT: 聚合数据,但Tick级别延迟不稳定
- Tardis: 专门针对交易所原始数据的API,支持OKX、Bybit等主流交易所的完整Orderbook和Trade数据
OKX永续合约的Tick数据特点:
- 平均每秒300-800笔成交
- 盘口深度变化频繁
- 资金费率更新周期为8小时
Tardis API环境配置
# tardis_api_usage.py
依赖安装
pip install tardis-client aiohttp pandas numpy
import asyncio
from tardis_client import TardisClient, Message
from dataclasses import dataclass
from typing import List, Dict, Optional
import pandas as pd
from datetime import datetime, timedelta
import json
import hashlib
@dataclass
class OKXTickData:
"""OKX永续合约Tick数据结构"""
exchange: str = "okx"
symbol: str = ""
timestamp: int = 0
local_timestamp: int = 0
price: float = 0.0
amount: float = 0.0
side: str = "" # buy/sell
order_id: int = 0
fee: float = 0.0
fee_currency: str = "USDT"
class TardisDataFetcher:
"""Tardis API数据获取器"""
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "wss://tardis.io"
self.exchange = "okx"
self.channels = ["trades", "books"] # 成交和订单簿
async def fetch_trades(self, symbol: str, start: datetime, end: datetime) -> List[OKXTickData]:
"""获取指定时间范围的成交数据"""
client = TardisClient(api_key=self.api_key)
trades = []
async for message in client.stream(
exchange=self.exchange,
channel="trades",
symbols=[f"{symbol}-usdt-swap"] # OKX永续合约命名规则
):
if message.type == "trade":
trade = OKXTickData(
exchange=self.exchange,
symbol=symbol,
timestamp=message.timestamp,
local_timestamp=int(datetime.now().timestamp() * 1000),
price=float(message.trade["price"]),
amount=float(message.trade["amount"]),
side=message.trade["side"],
order_id=message.trade.get("orderId", 0),
fee=float(message.trade.get("fee", 0)),
fee_currency=message.trade.get("feeCurrency", "USDT")
)
trades.append(trade)
return trades
使用示例
fetcher = TardisDataFetcher(api_key="YOUR_TARDIS_API_KEY")
获取BTC永续合约过去1小时的Tick数据
start_time = datetime.now() - timedelta(hours=1)
end_time = datetime.now()
trades = await fetcher.fetch_trades("BTC", start_time, end_time)
print(f"获取到 {len(trades)} 条Tick数据")
生产级回测引擎架构
一个合格的回测引擎需要解决以下核心问题:
- 数据重放: 严格按时间顺序重放历史数据
- 滑点模拟: 真实模拟成交滑点
- 手续费计算: 包含maker/taker费率差异
- 资金管理: 支持仓位管理和强平逻辑
- 性能优化: 支持千万级Tick数据的快速回测
# backtest_engine.py
import numpy as np
from dataclasses import dataclass, field
from typing import List, Dict, Tuple, Optional, Callable
from enum import Enum
from collections import deque
import heapq
import time
class OrderSide(Enum):
BUY = "BUY"
SELL = "SELL"
class PositionSide(Enum):
LONG = "LONG"
SHORT = "SHORT"
FLAT = "FLAT"
@dataclass
class Order:
"""订单数据结构"""
order_id: str
symbol: str
side: OrderSide
price: float
amount: float
timestamp: int
status: str = "pending"
filled_price: float = 0.0
filled_amount: float = 0.0
fee: float = 0.0
@dataclass
class Position:
"""持仓数据结构"""
symbol: str
side: PositionSide
entry_price: float
amount: float
leverage: int
unrealized_pnl: float = 0.0
realized_pnl: float = 0.0
@dataclass
class BacktestConfig:
"""回测配置"""
initial_capital: float = 10000.0 # 初始资金 USDT
maker_fee: float = 0.0002 # Maker费率 0.02%
taker_fee: float = 0.0005 # Taker费率 0.05%
slippage: float = 0.0003 # 滑点 0.03%
funding_rate: float = 0.0001 # 资金费率
max_position: float = 0.3 # 最大仓位比例 30%
risk_free_rate: float = 0.03 # 无风险利率
@dataclass
class BacktestResult:
"""回测结果"""
total_trades: int = 0
winning_trades: int = 0
losing_trades: int = 0
win_rate: float = 0.0
total_pnl: float = 0.0
max_drawdown: float = 0.0
sharpe_ratio: float = 0.0
sortino_ratio: float = 0.0
annual_return: float = 0.0
annual_volatility: float = 0.0
profit_factor: float = 0.0
avg_trade_pnl: float = 0.0
max_consecutive_wins: int = 0
max_consecutive_losses: int = 0
class BacktestEngine:
"""高性能回测引擎"""
def __init__(self, config: BacktestConfig):
self.config = config
self.capital = config.initial_capital
self.initial_capital = config.initial_capital
self.position: Optional[Position] = None
self.orders: List[Order] = []
self.equity_curve: List[float] = []
self.trades: List[Dict] = []
self.order_book: deque = deque(maxlen=1000) # 滚动订单簿
# 性能优化:使用numpy数组
self.price_history: np.ndarray = np.zeros(10000)
self.volume_history: np.ndarray = np.zeros(10000)
self.pnl_history: np.ndarray = np.zeros(10000)
self.pointer = 0
# 统计变量
self.wins = 0
self.losses = 0
self.consecutive_wins = 0
self.consecutive_losses = 0
self.max_consecutive_wins = 0
self.max_consecutive_losses = 0
def process_tick(self, tick: OKXTickData) -> Optional[Dict]:
"""处理单条Tick数据"""
# 更新价格历史
self.price_history[self.pointer % 10000] = tick.price
self.volume_history[self.pointer % 10000] = tick.amount
self.pointer += 1
# 更新持仓盈亏
if self.position and self.position.amount > 0:
if self.position.side == PositionSide.LONG:
self.position.unrealized_pnl = (
tick.price - self.position.entry_price
) * self.position.amount
else:
self.position.unrealized_pnl = (
self.position.entry_price - tick.price
) * self.position.amount
# 记录权益曲线
current_equity = self.capital + (
self.position.unrealized_pnl if self.position else 0
)
self.equity_curve.append(current_equity)
return None
def execute_order(self, order: Order, current_price: float) -> Order:
"""执行订单"""
order.filled_price = current_price * (1 + self.config.slippage) if order.side == OrderSide.BUY else current_price * (1 - self.config.slippage)
order.filled_amount = order.amount
# 计算手续费
fee = order.filled_price * order.filled_amount * self.config.taker_fee
order.fee = fee
self.capital -= fee
# 更新持仓
if order.side == OrderSide.BUY:
if self.position and self.position.side == PositionSide.SHORT:
# 平空仓
pnl = (self.position.entry_price - order.filled_price) * self.position.amount
self.capital += self.position.amount * self.position.entry_price + pnl
self._record_trade(pnl, self.position.entry_price, order.filled_price)
self.position = None
elif not self.position:
# 开多仓
self.position = Position(
symbol=order.symbol,
side=PositionSide.LONG,
entry_price=order.filled_price,
amount=order.amount,
leverage=1
)
self.capital -= order.filled_price * order.amount
else:
if self.position and self.position.side == PositionSide.LONG:
# 平多仓
pnl = (order.filled_price - self.position.entry_price) * self.position.amount
self.capital += self.position.amount * self.position.entry_price + pnl
self._record_trade(pnl, self.position.entry_price, order.filled_price)
self.position = None
elif not self.position:
# 开空仓
self.position = Position(
symbol=order.symbol,
side=PositionSide.SHORT,
entry_price=order.filled_price,
amount=order.amount,
leverage=1
)
self.capital -= order.filled_price * order.amount
order.status = "filled"
return order
def _record_trade(self, pnl: float, entry: float, exit: float):
"""记录交易"""
if pnl > 0:
self.wins += 1
self.consecutive_wins += 1
self.consecutive_losses = 0
self.max_consecutive_wins = max(self.max_consecutive_wins, self.consecutive_wins)
else:
self.losses += 1
self.consecutive_losses += 1
self.consecutive_wins = 0
self.max_consecutive_losses = max(self.max_consecutive_losses, self.consecutive_losses)
self.trades.append({
"pnl": pnl,
"entry": entry,
"exit": exit,
"timestamp": int(time.time() * 1000)
})
def calculate_results(self) -> BacktestResult:
"""计算回测结果"""
equity = np.array(self.equity_curve)
returns = np.diff(equity) / equity[:-1]
# 最大回撤
running_max = np.maximum.accumulate(equity)
drawdown = (equity - running_max) / running_max
max_drawdown = abs(np.min(drawdown))
# 夏普比率
annual_return = np.mean(returns) * 365 * 24
annual_volatility = np.std(returns) * np.sqrt(365 * 24)
sharpe_ratio = (annual_return - self.config.risk_free_rate) / annual_volatility if annual_volatility > 0 else 0
# 索提诺比率
downside_returns = returns[returns < 0]
downside_std = np.std(downside_returns) * np.sqrt(365 * 24) if len(downside_returns) > 0 else 1
sortino_ratio = (annual_return - self.config.risk_free_rate) / downside_std if downside_std > 0 else 0
# 盈利因子
win_amounts = [t["pnl"] for t in self.trades if t["pnl"] > 0]
loss_amounts = [abs(t["pnl"]) for t in self.trades if t["pnl"] < 0]
profit_factor = sum(win_amounts) / sum(loss_amounts) if sum(loss_amounts) > 0 else 0
total_pnl = sum(t["pnl"] for t in self.trades)
total_trades = self.wins + self.losses
return BacktestResult(
total_trades=total_trades,
winning_trades=self.wins,
losing_trades=self.losses,
win_rate=self.wins / total_trades if total_trades > 0 else 0,
total_pnl=total_pnl,
max_drawdown=max_drawdown,
sharpe_ratio=sharpe_ratio,
sortino_ratio=sortino_ratio,
annual_return=annual_return,
annual_volatility=annual_volatility,
profit_factor=profit_factor,
avg_trade_pnl=total_pnl / total_trades if total_trades > 0 else 0,
max_consecutive_wins=self.max_consecutive_wins,
max_consecutive_losses=self.max_consecutive_losses
)
使用示例
config = BacktestConfig(
initial_capital=10000.0,
maker_fee=0.0002,
taker_fee=0.0005,
slippage=0.0003
)
engine = BacktestEngine(config)
处理Tick数据
for tick in trades[:1000]: # 取前1000条测试
engine.process_tick(tick)
results = engine.calculate_results()
print(f"总交易次数: {results.total_trades}")
print(f"胜率: {results.win_rate:.2%}")
print(f"夏普比率: {results.sharpe_ratio:.2f}")
print(f"最大回撤: {results.max_drawdown:.2%}")
print(f"总盈亏: {results.total_pnl:.2f} USDT")
并发处理与性能优化
处理千万级Tick数据时,单线程已经无法满足需求。我使用了以下优化策略:
# high_performance_backtest.py
import asyncio
import aiofiles
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
from typing import List, Tuple
import numpy as np
import mmap
import struct
from dataclasses import dataclass
import os
@dataclass
class ChunkResult:
"""分块计算结果"""
start_idx: int
end_idx: int
pnl: float
trades_count: int
max_drawdown: float
class ParallelBacktestEngine:
"""并行回测引擎 - 支持多进程处理"""
def __init__(self, config: BacktestConfig, workers: int = 8):
self.config = config
self.workers = workers
self.chunk_size = 100000 # 每块10万条Tick
def process_chunk(self, chunk_data: np.ndarray) -> ChunkResult:
"""处理单个数据块"""
pnl = 0.0
trades_count = 0
equity = self.config.initial_capital
max_dd = 0.0
peak = equity
for tick in chunk_data:
price = tick[0]
volume = tick[1]
# 简化的PnL计算
if trades_count > 0:
pnl += (price - chunk_data[0][0]) * volume * 0.01
equity = self.config.initial_capital + pnl
peak = max(peak, equity)
dd = (peak - equity) / peak
max_dd = max(max_dd, dd)
return ChunkResult(
start_idx=0,
end_idx=len(chunk_data),
pnl=pnl,
trades_count=trades_count,
max_drawdown=max_dd
)
async def run_parallel(self, tick_file: str) -> BacktestResult:
"""并行运行回测"""
# 使用内存映射文件处理大文件
with open(tick_file, 'rb') as f:
with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mm:
# 读取数据
data = np.frombuffer(mm, dtype=np.float64)
data = data.reshape(-1, 2) # [price, volume]
chunks = [
data[i:i + self.chunk_size]
for i in range(0, len(data), self.chunk_size)
]
# 多进程处理
with ProcessPoolExecutor(max_workers=self.workers) as executor:
results = list(executor.map(self.process_chunk, chunks))
# 合并结果
total_pnl = sum(r.pnl for r in results)
total_trades = sum(r.trades for r in results)
max_dd = max(r.max_drawdown for r in results)
return BacktestResult(
total_trades=total_trades,
total_pnl=total_pnl,
max_drawdown=max_dd
)
异步数据下载和预处理
async def download_and_preprocess(symbol: str, start: datetime, end: datetime):
"""异步下载并预处理数据"""
import aiohttp
async with aiohttp.ClientSession() as session:
# 下载成交数据
trades_url = f"https://api.tardis.io/v1/replay/{symbol}"
params = {
"from": int(start.timestamp()),
"to": int(end.timestamp()),
"format": "binary"
}
async with session.get(trades_url, params=params) as resp:
data = await resp.read()
# 保存为二进制格式(节省空间,加快读取)
async with aiofiles.open(f"{symbol}_ticks.bin", "wb") as f:
await f.write(data)
print(f"数据下载完成,大小: {os.path.getsize(f'{symbol}_ticks.bin') / 1024 / 1024:.2f} MB")
性能基准测试
async def benchmark():
"""性能基准测试"""
import time
config = BacktestConfig()
engine = ParallelBacktestEngine(config, workers=8)
# 生成100万条模拟数据
np.random.seed(42)
prices = 50000 + np.cumsum(np.random.randn(1000000) * 10)
volumes = np.random.exponential(1, 1000000)
test_data = np.column_stack([prices, volumes])
start_time = time.time()
result = engine.process_chunk(test_data)
elapsed = time.time() - start_time
print(f"处理100万条Tick耗时: {elapsed:.2f}秒")
print(f"处理速度: {1000000 / elapsed:.0f} ticks/秒")
print(f"内存占用峰值: {np.round(nppeak(config.initial_capital) / 1024 / 1024, 2)} MB")
滑点优化与实盘模拟
回测结果与实盘最大的差距往往来自滑点。OKX永续合约的实际滑点会因流动性深度而变化:
# slippage_optimizer.py
import numpy as np
from typing import Dict, List, Tuple
class SlippageModel:
"""基于订单簿深度的滑点模型"""
def __init__(self, orderbook_file: str = None):
self.orderbook_data = self._load_orderbook(orderbook_file) if orderbook_file else None
def _load_orderbook(self, file: str) -> Dict:
"""加载订单簿数据"""
import json
with open(file, 'r') as f:
return json.load(f)
def calculate_slippage(
self,
symbol: str,
side: str,
amount: float,
base_price: float
) -> Tuple[float, float]:
"""
计算滑点
Returns:
(expected_slippage_pct, worst_case_slippage_pct)
"""
if self.orderbook_data and symbol in self.orderbook_data:
return self._calculate_from_depth(amount, base_price)
# 默认滑点模型(基于经验数据)
# 流动性好的币种(BTC/ETH)滑点较低
if symbol in ["BTC", "ETH"]:
base_slippage = 0.0001 # 0.01%
else:
base_slippage = 0.0003 # 0.03%
# 订单大小对滑点的影响(非线性)
size_factor = 1 + np.log1p(amount / 1.0) * 0.5
expected = base_slippage * size_factor
worst = expected * 2
return expected, worst
def _calculate_from_depth(
self,
amount: float,
base_price: float
) -> Tuple[float, float]:
"""基于实际订单簿深度计算"""
bids = self.orderbook_data.get("bids", [])
asks = self.orderbook_data.get("asks", [])
remaining = amount
cost = 0.0
for price, quantity in asks[:50]: # 取前50档
fill = min(remaining, quantity)
cost += fill * price
remaining -= fill
if remaining <= 0:
break
if remaining > 0:
# 超过订单簿深度,使用最差价格
cost += remaining * asks[-1][0]
avg_price = cost / amount
slippage = (avg_price - base_price) / base_price
return slippage, slippage * 1.5
class MarketImpactModel:
"""市场冲击模型"""
@staticmethod
def estimate_impact(
amount: float,
daily_volume: float,
volatility: float
) -> float:
"""
估算市场冲击
公式基于Almgren-Chriss模型
"""
# 参与率
participation_rate = amount / daily_volume
# 临时冲击系数
temp_impact = 0.1 * volatility * np.sqrt(participation_rate)
# 永久冲击系数
perm_impact = 0.1 * volatility * participation_rate
return temp_impact + perm_impact
动态滑点优化器
class AdaptiveSlippageOptimizer:
"""自适应滑点优化器"""
def __init__(self, lookback_periods: int = 100):
self.lookback = lookback_periods
self.slippage_history: List[float] = []
self.volume_history: List[float] = []
def update(self, executed_price: float, expected_price: float, volume: float):
"""更新滑点历史"""
slippage = abs(executed_price - expected_price) / expected_price
self.slippage_history.append(slippage)
self.volume_history.append(volume)
if len(self.slippage_history) > self.lookback:
self.slippage_history.pop(0)
self.volume_history.pop(0)
def get_estimated_slippage(self, amount: float) -> float:
"""获取估计滑点"""
if not self.slippage_history:
return 0.0003 # 默认0.03%
# 加权平均(最近的数据权重更高)
weights = np.linspace(0.5, 1.5, len(self.slippage_history))
weights /= weights.sum()
base_slippage = np.average(self.slippage_history, weights=weights)
# 根据订单大小调整
avg_volume = np.mean(self.volume_history)
size_factor = 1 + np.log1p(amount / avg_volume) * 0.3
return base_slippage * size_factor
使用示例
optimizer = AdaptiveSlippageOptimizer()
模拟执行
base_price = 50000.0
order_amount = 1.0 # 1 BTC
estimated_slippage = optimizer.get_estimated_slippage(order_amount)
expected_execution_cost = base_price * order_amount * estimated_slippage
print(f"预估滑点: {estimated_slippage:.4%}")
print(f"预估执行成本: ${expected_execution_cost:.2f}")
AI驱动的策略优化
传统回测只能告诉我们策略在过去的表现,而AI可以帮我们找到最优参数和识别隐藏的交易机会。在策略优化阶段,我使用HolySheep AI的API来加速分析流程。
# strategy_optimizer.py
import asyncio
import aiohttp
from typing import Dict, List, Optional
import json
import numpy as np
class HolySheepOptimizer:
"""使用HolySheep AI优化交易策略"""
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
self.model = "gpt-4.1"
async def analyze_backtest_results(
self,
backtest_data: Dict,
strategy_description: str
) -> Dict:
"""
使用AI分析回测结果并提供优化建议
相比直接使用OpenAI API,HolySheep AI成本降低85%以上
GPT-4.1在HolySheep价格为 $8/MTok
"""
prompt = f"""
作为量化交易策略专家,分析以下回测结果并提供优化建议:
策略描述: {strategy_description}
回测数据:
- 总交易次数: {backtest_data.get('total_trades', 0)}
- 胜率: {backtest_data.get('win_rate', 0):.2%}
- 夏普比率: {backtest_data.get('sharpe_ratio', 0):.2f}
- 最大回撤: {backtest_data.get('max_drawdown', 0):.2%}
- 盈亏比: {backtest_data.get('profit_factor', 0):.2f}
- 总盈亏: ${backtest_data.get('total_pnl', 0):.2f}
请分析:
1. 策略的主要优势和劣势
2. 参数优化的建议
3. 风险管理的改进方案
4. 可能的过拟合风险
"""
async with aiohttp.ClientSession() as session:
async with session.post(
f"{self.base_url}/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"model": self.model,
"messages": [
{"role": "system", "content": "你是一位专业的量化交易策略专家。"},
{"role": "user", "content": prompt}
],
"temperature": 0.3,
"max_tokens": 2000
}
) as resp:
result = await resp.json()
return {
"analysis": result["choices"][0]["message"]["content"],
"usage": result.get("usage", {})
}
async def generate_trading_signals(
self,
market_data: Dict,
strategy_rules: List[str]
) -> Dict:
"""
使用AI辅助生成交易信号
适合快速验证策略思路
"""
prompt = f"""
基于以下市场数据和策略规则,判断是否产生交易信号:
市场数据:
- 当前价格: {market_data.get('price', 0)}
- 24h成交量: {market_data.get('volume', 0)}
- 波动率: {market_data.get('volatility', 0):.2%}
- RSI: {market_data.get('rsi', 0):.2f}
- MACD: {market_data.get('macd', 0)}
策略规则:
{chr(10).join([f"- {rule}" for rule in strategy_rules])}
请给出:
1. 信号判断(买入/卖出/观望)
2. 置信度评分(0-100)
3. 入场点位建议
4. 止损/止盈建议
"""
async with aiohttp.ClientSession() as session:
async with session.post(
f"{self.base_url}/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"model": "deepseek-v3.2", # 使用更便宜的模型进行信号判断
"messages": [
{"role": "user", "content": prompt}
],
"temperature": 0.2,
"max_tokens": 500
}
) as resp:
result = await resp.json()
return {
"signal": result["choices"][0]["message"]["content"],
"model_used": "deepseek-v3.2",
"cost_per_call": 0.0001 # 约$0.0001/次
}
async def optimize_parameters(
self,
param_ranges: Dict[str, tuple],
objective: str = "sharpe_ratio"
) -> List[Dict]:
"""
使用AI辅助参数优化
通过自然语言理解参数之间的关系
"""
prompt = f"""
优化以下策略参数,目标是最大化 {objective}:
参数范围:
{json.dumps(param_ranges, indent=2)}
请给出:
1. 推荐的参数组合
2. 每个参数的合理范围
3. 参数敏感性分析
4. 参数之间的交互效应
"""
async with aiohttp.ClientSession() as session:
async with session.post(
f"{self.base_url}/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"model": self.model,
"messages": [
{"role": "user", "content": prompt}
],
"temperature": 0.4,
"max_tokens": 1500
}
) as resp:
result = await resp.json()
return {
"recommendation": result["choices"][0]["message"]["content"],
"estimated_savings": "$15-30/次 vs OpenAI" # 85%成本节省
}
使用示例
async def main():
optimizer = HolySheepOptimizer(api_key="YOUR_HOLYSHEEP_API_KEY")
# 分析回测结果
backtest_data = {
"total_trades": 1523,
"win_rate": 0.58,
"sharpe_ratio": 1.85,
"max_drawdown": 0.12,
"profit_factor": 1.92,
"total_pnl": 15420.50
}
result = await optimizer.analyze_backtest_results(
backtest_data,
"OKX永续合约布林带突破策略"
)
print("=== AI策略分析结果 ===")
print(result["analysis"])
print(f"\nAPI调用费用: ${result['usage'].get('total_tokens', 0) / 1000000 * 8:.4f}")
# 生成交易信号
market_data = {
"price": 52450.50,
"volume": 1250000000,
"volatility": 0.023,
"rsi": 68.5,
"macd": 125.30
}
strategy_rules = [
"布林带上轨突破买入",
"RSI>70且MACD死叉卖出",
"持仓超过24小时强制平仓"
]
signal = await optimizer.generate_trading_signals(market_data, strategy_rules)
print("\n=== 交易信号 ===")
print(signal["signal"])
print(f"模型: {signal['model_used']}, 单次成本: {signal['cost_per_call']}")
asyncio.run(main())
完整回测流程实战
下面是一个完整的实盘级回测案例,包含数据获取、策略执行、结果分析全流程:
# full_backtest_pipeline.py
import asyncio
import pandas as pd
from datetime import datetime, timedelta
from typing import List, Optional
import json
class OKXBacktestPipeline:
"""OKX永续合约完整回测流水线"""
def __init__(
self,
tardis_key: str,
holysheep_key: str,
symbol: str = "BTC"
):
self.tardis_key = tardis_key
self.holysheep_key = holysheep_key
self.symbol = symbol
self.fetcher = TardisDataFetcher(tardis_key)
self.backtest_engine = BacktestEngine(BacktestConfig())
self.ai_optimizer = HolySheepOptimizer(holysheep_key)
async def run_full_backtest(
self,
start_date: datetime,
end_date: datetime,
strategy_params: dict
) -> dict:
"""运行完整回测流程"""
print(f"开始回测: {self.symbol} {start_date} -> {end_date}")
# 阶段1: 数据获取
print("阶段1: 获取Tick数据...")
tick_data = await self._fetch_data(start_date, end_date)
print(f" 获取到 {len(tick_data)} 条Tick数据")
# 阶段2: 数据预处理
print("阶段2: 预处理数据...")
processed_data = self._preprocess_data(tick_data)
print(f" 处理后 {len(processed_data)} 条有效数据")
# 阶段3: 策略回测
print("阶段3: 运行回测...")
backtest_result = await self._run_backtest(processed_data, strategy_params)
print(f" 总交易: {backtest_result.total_trades}")
print(f" 胜率: {backtest_result.win_rate:.2%}")
print(f" 夏普: