基础入门
本讲把最小价格序列、买入信号和卖出信号正式接到 vectorbt 的回测入口上,使用 Portfolio.from_signals 跑出第一轮可继续读取结果的回测对象。目标是让入门者第一次完整走通从规则表达进入可执行回测的闭环。
第 6 讲终于把前面几讲准备好的数据、均线和买卖信号真正接到 vectorbt 的回测入口上。目标很具体:用一份最小价格序列、一列买入信号和一列卖出信号,跑出第一轮向量化回测结果对象。
学完这一讲后,你可以直接完成下面几件事:
from_signals 跑出一个最小回测对象。这是整套 vectorbt 入门短课第一次真正把“规则表达”推进成“可执行回测”。
对新手来说,最容易犯的错误之一,就是一碰到回测就想把手续费、滑点、仓位比例、参数扫描、多资产组合一口气全加进去。这样做表面上很完整,实际上会让你根本分不清回测失败到底是输入错了、信号错了,还是参数太多把问题淹没了。
第 6 讲故意强调“第一轮”,意思就是先拿最少的输入把回测对象跑出来。只要这一步走通,你后面再往里加别的设置时,至少知道最小闭环本身是成立的。
bt_df = signal_df.copy()
print(bt_df[['date', 'close', 'buy_signal', 'sell_signal']].head(15))
此时表里至少应该有四列:
dateclosebuy_signalsell_signal如果这四列还没齐,第 6 讲就不应该直接往回测入口推进。
前面几讲准备的价格和信号,到这一讲才第一次真正接入回测引擎。下面四步的重点是先把入口跑通。
assert len(bt_df['close']) == len(bt_df['buy_signal'])
assert len(bt_df['close']) == len(bt_df['sell_signal'])
这一步虽然简单,但很重要。向量化回测的前提之一,就是价格和信号在同一组样本位置上对齐。如果长度都不一致,后面结果即使强行跑通,也没有解释意义。
bt_df = bt_df.set_index('date')
前面几讲为了便于查看,常把日期做成普通列;而进入回测入口时,把日期设成索引通常会更自然,因为这样价格和信号都会在时间轴上对齐得更直观。
import vectorbt as vbt
portfolio = vbt.Portfolio.from_signals(
close=bt_df['close'],
entries=bt_df['buy_signal'],
exits=bt_df['sell_signal']
)
这就是第 6 讲最核心的一步。它把前面已经准备好的价格和信号,正式交给 vectorbt 生成一个组合回测对象。
print(type(portfolio))
print(portfolio.value().head())
此时别急着解读太多绩效指标,先确认两个事实:
这一讲的验证标准很朴素:对象能生成、净值能取出、统计能打印,就说明最小回测链路已经接上了。
assert portfolio is not None
value_series = portfolio.value()
print(value_series.head())
assert len(value_series) == len(bt_df)
print(portfolio.stats())
第 6 讲不要求你现在把统计全读懂,但它应该至少能被取出来。
你可以把 entries 和 exits 的样本位置再对照一次,确认它们确实是你上一讲手工检查过的那两列。
第一次看到 portfolio 对象时,不放心很正常。关键是把“对象生成”和“结果解释”分成两步看,不要混在一起判断。
这是正常疑问。最稳的办法不是猜,而是回头看 buy_signal 和 sell_signal 的触发位置,再看 portfolio.value() 是否在这些位置附近开始出现变化。
第 6 讲不用急着全部理解。你当前只要先确认回测对象已经能吐出结果,下一讲我们再专门看收益、回撤和交易次数。
这不代表第 6 讲失败。入门阶段的目标不是立刻得到“优秀策略”,而是确认一条最小策略从价格、均线、信号一路接到了回测引擎。
可以,但不建议在第 6 讲一开始就加。先把最小回测闭环跑通,再一点点加设置,会更稳。
value() 和 stats(),不必马上看所有输出。import vectorbt as vbt
import pandas as pd
def run_first_backtest(df: pd.DataFrame):
work = df.set_index('date').copy()
return vbt.Portfolio.from_signals(
close=work['close'],
entries=work['buy_signal'],
exits=work['sell_signal']
)
portfolio = run_first_backtest(signal_df)
print(portfolio.value().head())
这样你后面换样本、换窗口、换信号时,都能沿用同一个最小入口函数。
很多人会把“第一轮回测”理解成只是得到一张净值曲线。但对 vectorbt 入门来说,第 6 讲真正重要的,是你第一次得到一个后面可以持续取各种结果的对象链路。也就是说,你现在手里的不只是几个孤立数组,而是一个能继续产出净值、统计和交易记录的 portfolio 对象。
这个区别很重要。因为一旦对象链路跑通,后面第 7 讲和第 8 讲做的事情,本质上都不再是“重新搭系统”,而只是继续从这个对象里读取结果、比较设置。
第 7 讲要看的收益、回撤和交易次数,都要建立在第 6 讲这个 portfolio 对象已经成立的前提上。所以第 6 讲最关键的完成标志,不是“图看起来很好”,而是“对象已经生成,结果已经可取”。只要这一步稳了,后面解读指标就会顺得多。
如果你现在已经能把 close、buy_signal、sell_signal 交给 Portfolio.from_signals,并拿回一个可继续查看净值和统计的对象,那第 6 讲就算完成。
本讲是《vectorbt回测入门短课》的第 6/8 讲,当前主题是《跑第一轮向量化回测》。
上一讲:第 5 讲《构造卖出信号》。
下一讲:第 7 讲《查看收益回撤和交易次数》。
后续安排:第 8 讲《比较5日和10日窗口》。
风险揭示与免责声明
本页面内容仅用于量化研究与技术交流,旨在展示研究方法与流程,不构成对任何金融产品、证券或衍生品的要约、招揽、推荐或保证。
本文所涉历史数据、回测结果与示例参数不代表未来表现,也不应作为投资决策依据。
市场存在波动、流动性与执行偏差等不确定性,任何策略均可能出现收益波动或阶段性失效。
读者应结合自身风险承受能力进行独立判断,并在必要时咨询持牌专业机构意见。