夜间深度回测首次完整跑通

本文最后更新于 2026年8月26日 凌晨


title: “夜间深度回测首次完整跑通”
date: 2026-08-26 22:30:00
tags: [回测, 量化交易, 前后端, 配置]
categories: [技术教程]

三个晚上,我一直在跟前后端通信和回测引擎的跨日数据对齐较劲。昨晚终于跑通了深度回测,跨三日,全量数据,一次通过。整个过程不复杂,但踩坑不少。这篇把完整步骤写下来,帮后来人省点时间。


测了什么

所谓“深度回测”,不是简单的历史数据点一下。我做的回测任务是:

  • 使用 Backtrader 作为回测引擎
  • 从本地数据库加载 3 年日线数据(约 750 个交易日)
  • 策略逻辑是动量反转 + 均线交叉,每个交易日生成信号
  • 回测跨三日:从 2024-01-012026-08-26,按日频执行
  • 结果通过 Flask API 返回给前端 Vue3 页面展示

之前卡在两点:一是后端回测跑完前端收不到结果(WebSocket 握手失败),二是跨日数据在回测引擎里时间戳对齐出错(不同交易所的节假日不一致)。这次全部解决。


硬件环境

先说下跑在什么机器上,因为显存占满可能影响回测中并行计算。

项目
服务器 YOUR_SERVER_IP
显卡 2× RTX 2080 Ti 魔改版,单卡 22 GB,双卡共 44 GB
推理引擎 llama.cpp(用于回测中辅助生成分析注释)
代理层

回测引擎本身不依赖 GPU,但我在回测完成后会调用 Qwen 模型对结果生成策略评价,所以用了 llama.cpp 部署的 Qwen3.5-35B-A3B,实测速度 104 t/s


前置条件

  • Python 3.10+
  • Backtrader 1.9.76+
  • Flask 2.3 + Flask-SocketIO
  • Node.js 18 + Vue3 + Vite
  • MySQL 8.0(存储历史数据)
  • 本机已配置好 llama.cpp 服务(可选)

操作步骤

第一步:搭建回测引擎

Backtrader 的配置核心是 cerebro。这里我直接上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import backtrader as bt

class MyStrategy(bt.Strategy):
params = dict(
period=20,
rsi_period=14,
rsi_upper=70,
rsi_lower=30,
)

def __init__(self):
self.sma = bt.indicators.SMA(self.data.close, period=self.params.period)
self.rsi = bt.indicators.RSI(self.data.close, period=self.params.rsi_period)

def next(self):
if self.rsi[0] < self.params.rsi_lower and self.data.close[0] > self.sma[0]:
self.buy(size=100)
elif self.rsi[0] > self.params.rsi_upper and self.data.close[0] < self.sma[0]:
self.sell(size=100)

关键:回测引擎必须支持跨日数据。我用 bt.feeds.PandasData 加载时,确保数据框的索引是 datetime 类型,并且时间戳对齐到交易日中午 12:00(避免跨日边界问题)。

第二步:前后端通信

之前踩坑:前端用 socket.io-client 4.x,后端用 Flask-SocketIO 5.x,版本不匹配导致握手失败。解决方案:统一版本。后端我用 flask-socketio==5.3.4,前端 socket.io-client==4.6.1

后端代码片段:

1
2
3
4
5
6
7
8
9
10
11
from flask_socketio import SocketIO, emit
from flask import Flask

app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*")

@socketio.on('start_backtest')
def handle_backtest(data):
# 运行回测(耗时操作)
result = run_backtest(data['symbol'], data['start_date'], data['end_date'])
emit('backtest_result', result)

前端 Vue3 组件:

1
2
3
4
5
6
import { io } from 'socket.io-client'
const socket = io('http://YOUR_SERVER_IP:5000')\nsocket.emit('start_backtest', { symbol: 'AAPL', start_date: '2024-01-01', end_date: '2026-08-26' })
socket.on('backtest_result', (data) => {
this.result = data
this.loading = false
})

第三步:跨日数据对齐

这个问题最隐蔽。美股和港股节假日不同,直接用 pandas.date_range 会漏掉交易日。我改用 pandas_market_calendars 获取纽交所的交易日历:

1
2
3
4
import pandas_market_calendars as mcal
cal = mcal.get_calendar('NYSE')
schedule = cal.schedule(start_date='2024-01-01', end_date='2026-08-26')
trading_days = schedule.index

然后只保留这些交易日的数据。回测引擎里 next() 方法只在这些交易日被调用,不会出现跨日间隔过大导致策略误判。

第四步:运行回测

写一个入口脚本 run_backtest.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import backtrader as bt
from datetime import datetime
import pandas as pd

def run_backtest(symbol, start, end):
# 从数据库加载数据
df = pd.read_sql(f"SELECT * FROM daily_klines WHERE symbol='{symbol}' AND date BETWEEN '{start}' AND '{end}'",
con=engine, index_col='date')
df.index = pd.to_datetime(df.index)
# 过滤非交易日
# ...(代码略)
cerebro = bt.Cerebro()
data = bt.feeds.PandasData(dataname=df)
cerebro.adddata(data)
cerebro.addstrategy(MyStrategy)
cerebro.broker.setcash(100000.0)
result = cerebro.run()
# 返回分析结果(收益率、胜率等)
return {'final_value': cerebro.broker.getvalue(), 'total_return': ...}

在服务器上调用:

1
2
cd ~/backtest_project
python run_backtest.py --symbol AAPL --start 2024-01-01 --end 2026-08-26

踩过的坑

  1. WebSocket 版本不匹配:前后端 socket.io 版本一定要一致,否则连接成功但事件不触发。
  2. 数据对齐:直接用 pd.date_range 生成日期会包含非交易日,导致回测引擎在非交易日也调用 next(),结果全是空值。
  3. 显存占用:虽然回测不占 GPU,但 llama.cpp 推理时如果同时运行多个请求,会占满 44 GB 显存。我设置 --n-gpu-layers 33 只把部分层加载到 GPU,留出空间。
  4. 首次运行超时:回测 750 个交易日,Backtrader 默认单线程,耗时约 2 分钟。前端 WebSocket 超时默认 20 秒,我改成了 ping_timeout=120

验证

回测完成后,前端收到结果:

1
2
3
4
5
6
{
"final_value": 123456.78,
"total_return": 23.46%,
"sharpe_ratio": 1.234,
"max_drawdown": -15.6%
}

我在浏览器里看到了完整的净值曲线图、交易记录列表。跨三日,一次成功

激动截图:

回测结果截图:收益率曲线和交易记录


延伸

现在跑通了基础回测,下一步可以加入多周期、多品种并行回测,或者用 Qwen 模型对策略结果自动生成分析报告。不过那是后话了。


参考文献

  1. Backtrader 官方文档:https://www.backtrader.com/docu/
  2. Flask-SocketIO 文档:https://flask-socketio.readthedocs.io/
  3. pandas_market_calendars: https://github.com/rsheftel/pandas_market_calendars
  4. llama.cpp 部署指南:https://github.com/ggerganov/llama.cpp

夜间深度回测首次完整跑通
https://normdist.com/2026/08/26/ND-20260826-001-article/
作者
小瑞
发布于
2026年8月26日
许可协议