回测时要将数据导入vnpy
要进行多品种回测的时候还是挺麻烦的,
比如,我现在有10多个品种的1分钟csv文件,
回测时可以直接读取csv文件,然后用vnpy的回测代码执行,这样可以的么?
如果可以,要如何实现?
回测时要将数据导入vnpy
要进行多品种回测的时候还是挺麻烦的,
比如,我现在有10多个品种的1分钟csv文件,
回测时可以直接读取csv文件,然后用vnpy的回测代码执行,这样可以的么?
如果可以,要如何实现?
可以的。VeighNa 回测引擎本质上只是回放 history_data 列表里的 BarData 对象,数据从数据库加载只是默认行为。看完 vnpy_ctastrategy/backtesting.py 源码后,有两种实现思路:
回测流程是 load_data() → run_backtesting(),其中 load_data() 只是从数据库加载数据填充 engine.history_data。因此可以跳过 load_data(),自己从 CSV 构造 BarData 列表:
from datetime import datetime
import pandas as pd
from vnpy.trader.constant import Exchange, Interval
from vnpy.trader.object import BarData
from vnpy_ctastrategy.backtesting import BacktestingEngine
def load_bars_from_csv(
filepath: str,
symbol: str,
exchange: Exchange
) -> list[BarData]:
"""从CSV文件加载K线数据,转换为BarData列表"""
df: pd.DataFrame = pd.read_csv(filepath)
bars: list[BarData] = []
for row in df.itertuples():
bar: BarData = BarData(
symbol=symbol,
exchange=exchange,
datetime=datetime.strptime(row.datetime, "%Y-%m-%d %H:%M:%S"),
interval=Interval.MINUTE,
open_price=row.open,
high_price=row.high,
low_price=row.low,
close_price=row.close,
volume=row.volume,
gateway_name="CSV"
)
bars.append(bar)
return bars
# 回测引擎设置
engine: BacktestingEngine = BacktestingEngine()
engine.set_parameters(
vt_symbol="rb2505.SHFE",
interval=Interval.MINUTE,
start=datetime(2024, 1, 1),
end=datetime(2024, 12, 31),
rate=0.0001,
slippage=0.2,
size=10,
pricetick=0.2,
capital=1_000_000
)
from vnpy_ctastrategy.strategies.double_ma_strategy import DoubleMaStrategy
engine.add_strategy(DoubleMaStrategy, {})
# 跳过 load_data(),直接注入 CSV 数据
engine.history_data = load_bars_from_csv(
"rb2505_1min.csv", "rb2505", Exchange.SHFE
)
engine.run_backtesting()
engine.calculate_result()
engine.calculate_statistics()
engine.show_chart()
注意事项:
on_init() 里调用了 load_bar(10),回测模式下它仍然会去数据库查询历史数据(见 backtesting.py 的 load_bar 方法)。解决办法:on_init,注释掉 load_bar 调用(前提是你的 CSV 数据足够长,指标会在回放中自然预热);load_bar 方法返回空列表。如果之后还要做参数优化(run_bf_optimization 的多进程回测依赖数据库加载),建议用 DataManager 模块一次性批量导入 CSV 到数据库,之后回测直接读取,无需重复导入。DataManager 支持界面批量导入,也可以用脚本调用 database.save_bar_data(bars)。
如果你的需求是"一个策略同时交易多个品种、共享资金"(而不是逐品种单独回测),CTA 回测引擎不支持,应使用 vnpy_portfoliostrategy(组合策略模块),其回测引擎支持传入多个 vt_symbol 和对应的 history_data 字典。
参考来源:
vnpy_ctastrategy/backtesting.py(回测引擎源码)cta_backtester.md、cta_strategy.mdVeighNa_AI wrote:
可以的。VeighNa 回测引擎本质上只是回放
history_data列表里的BarData对象,数据从数据库加载只是默认行为。看完vnpy_ctastrategy/backtesting.py源码后,有两种实现思路:方案一:CSV 转 BarData,直接注入 history_data(不经过数据库)
回测流程是
load_data()→run_backtesting(),其中load_data()只是从数据库加载数据填充engine.history_data。因此可以跳过load_data(),自己从 CSV 构造 BarData 列表:from datetime import datetime import pandas as pd from vnpy.trader.constant import Exchange, Interval from vnpy.trader.object import BarData from vnpy_ctastrategy.backtesting import BacktestingEngine def load_bars_from_csv( filepath: str, symbol: str, exchange: Exchange ) -> list[BarData]: """从CSV文件加载K线数据,转换为BarData列表""" df: pd.DataFrame = pd.read_csv(filepath) bars: list[BarData] = [] for row in df.itertuples(): bar: BarData = BarData( symbol=symbol, exchange=exchange, datetime=datetime.strptime(row.datetime, "%Y-%m-%d %H:%M:%S"), interval=Interval.MINUTE, open_price=row.open, high_price=row.high, low_price=row.low, close_price=row.close, volume=row.volume, gateway_name="CSV" ) bars.append(bar) return bars # 回测引擎设置 engine: BacktestingEngine = BacktestingEngine() engine.set_parameters( vt_symbol="rb2505.SHFE", interval=Interval.MINUTE, start=datetime(2024, 1, 1), end=datetime(2024, 12, 31), rate=0.0001, slippage=0.2, size=10, pricetick=0.2, capital=1_000_000 ) from vnpy_ctastrategy.strategies.double_ma_strategy import DoubleMaStrategy engine.add_strategy(DoubleMaStrategy, {}) # 跳过 load_data(),直接注入 CSV 数据 engine.history_data = load_bars_from_csv( "rb2505_1min.csv", "rb2505", Exchange.SHFE ) engine.run_backtesting() engine.calculate_result() engine.calculate_statistics() engine.show_chart()注意事项:
- 数据排序:CSV 数据必须按时间升序排列,回测按列表顺序回放。
- 策略初始化问题:如果策略的
on_init()里调用了load_bar(10),回测模式下它仍然会去数据库查询历史数据(见backtesting.py的load_bar方法)。解决办法:
- 修改策略
on_init,注释掉load_bar调用(前提是你的 CSV 数据足够长,指标会在回放中自然预热);- 或者在你的脚本中重写引擎的
load_bar方法返回空列表。- 多品种循环:对 10 多个品种,只需把上述流程封装成函数,循环每个 CSV 文件执行即可。
方案二:导入数据库(官方推荐方式)
如果之后还要做参数优化(
run_bf_optimization的多进程回测依赖数据库加载),建议用 DataManager 模块一次性批量导入 CSV 到数据库,之后回测直接读取,无需重复导入。DataManager 支持界面批量导入,也可以用脚本调用database.save_bar_data(bars)。补充:真正的多品种联合回测
如果你的需求是"一个策略同时交易多个品种、共享资金"(而不是逐品种单独回测),CTA 回测引擎不支持,应使用 vnpy_portfoliostrategy(组合策略模块),其回测引擎支持传入多个
vt_symbol和对应的history_data字典。参考来源:
vnpy_ctastrategy/backtesting.py(回测引擎源码)- 官方文档
cta_backtester.md、cta_strategy.md
你提供的方案一很好,我测试成功了。
请问在这种代码形式回测下,测试生成的成交记录保存在哪里?
怎么查看?
在这种纯脚本回测模式下,成交记录只保存在内存中,不会写入任何文件。它们存放在回测引擎的 trades 字典里,回测结束后需要通过接口取出查看或导出。
BacktestingEngine 提供了 get_all_trades() 方法,返回成交记录列表(TradeData 对象列表):
engine.run_backtesting()
# 获取全部成交记录
trades = engine.get_all_trades()
for trade in trades:
print(
trade.datetime, trade.direction, trade.offset,
trade.price, trade.volume, trade.vt_orderid
)
方便后续用 Excel 或 pandas 分析:
import pandas as pd
def export_trades(engine: BacktestingEngine, filepath: str) -> None:
"""将回测成交记录导出为CSV"""
records: list[dict] = []
for trade in engine.get_all_trades():
records.append({
"成交时间": trade.datetime,
"合约代码": trade.vt_symbol,
"方向": trade.direction.value,
"开平": trade.offset.value,
"价格": trade.price,
"数量": trade.volume,
"委托号": trade.vt_orderid,
"成交号": trade.vt_tradeid,
})
df: pd.DataFrame = pd.DataFrame(records)
df.to_csv(filepath, index=False, encoding="utf-8-sig")
engine.run_backtesting()
export_trades(engine, "trades_rb2505.csv")
类似的接口还有:
| 方法 | 内容 |
|---|---|
get_all_trades() |
全部成交记录 |
get_all_orders() |
全部委托记录(含未成交/撤单) |
get_all_daily_results() |
逐日盈亏统计 |
calculate_statistics(df, output=True) |
汇总指标(胜率、盈亏比、回撤等),终端打印 |
另外,如果你希望像 CtaBacktester 界面那样直观地看到每笔开平仓在 K 线图上的标注,直接调用 engine.show_chart() 即可,图上会用箭头标出各笔成交。
参考来源:vnpy_ctastrategy/backtesting.py 源码中的 get_all_trades、update_trade、show_chart 方法。