Bastix
Resources

交易策略回测怎么做

交易策略回测必须先冻结规则、数据时点、样本与成本,再运行代码。本文提供一个只用 Python 标准库即可复算的合成数据示例,展示信号时序、单边成本与预期结果,并说明怎样检查前视、数据窥探、幸存者偏差与样本外污染。Bastix 没有统一回测引擎,不能把研究计算写成已上线产品能力。

交易策略回测的首要目标不是画收益曲线,而是证明规则、数据和代码在时间上自洽。最小样本都无法手算时,换成多年行情只会把错误藏得更深。本页先给一个合成数据例子,再说明怎样把同一协议迁移到获准的点时市场数据。

历史结果不能保证未来。回测只能回答“在固定数据版本、规则和假设下,代码产生了什么结果”,不能证明策略因果、可成交性或未来表现。

运行前冻结这张协议

项目本例填写值换真实数据时必须补充
研究目的检查信号时序和成本记账可证伪假设与决策用途
数据10 个合成收盘价来源、许可、时区、复权、披露时点、修订版本
规则收盘价高于含当日的 3 日简单均值则下一段持有完整阈值、标的池、再平衡和异常规则
成交当日收盘形成信号,按下一段收盘收益记账可用订单类型、延迟、成交量和价格假设
成本仓位每变化 1,扣 0.1%;最后平仓再扣 0.1%佣金、税费、价差、滑点、冲击和容量
参数搜索不搜索,只运行窗口 3候选总数、选择规则和搜索预算
结果用途仅验证实现样本内/验证/样本外及停止条件

本例的成交设定是教学简化,不代表现实中能在收盘价成交。把它换成真实研究时,必须按市场和订单逻辑重写。

合成数据与可运行代码

保存下面代码为任意本地 Python 文件即可运行;只使用标准库。数据是人工构造的,不包含真实证券或收益主张。

prices = [100, 101, 102, 100, 99, 103, 104, 102, 105, 106]
one_way_cost = 0.001

gross_equity = 1.0
net_equity = 1.0
previous_position = 0
rows = []

for t in range(len(prices) - 1):
    if t < 2:
        position = 0
        moving_average = None
    else:
        moving_average = sum(prices[t - 2:t + 1]) / 3
        position = 1 if prices[t] > moving_average else 0

    next_return = prices[t + 1] / prices[t] - 1
    turnover = abs(position - previous_position)
    cost = turnover * one_way_cost

    gross_equity *= 1 + position * next_return
    net_equity *= 1 + position * next_return - cost

    rows.append({
        "t": t,
        "price": prices[t],
        "moving_average": moving_average,
        "position_for_next_period": position,
        "next_return": next_return,
        "cost": cost,
    })
    previous_position = position

# 样本结束时强制把剩余仓位降为 0,并计一次单边成本
net_equity *= 1 - abs(previous_position) * one_way_cost

print("positions:", [row["position_for_next_period"] for row in rows])
print("gross_return:", round(gross_equity - 1, 8))
print("net_return:", round(net_equity - 1, 8))

预期输出为:

positions: [0, 0, 1, 0, 0, 1, 1, 0, 1]
gross_return: -0.0198798
net_return: -0.02574676

这组负结果是有意保留的。代码审查不应因为结果难看就换窗口、删价格或隐藏成本。若本地输出不同,先检查 Python 版本之外的代码差异、切片边界、成本扣除和最后平仓。

用这个例子做四个失败测试

前视测试

信号在 t 只能读取 prices[t] 及之前的数据,收益从 tt+1 发生。若移动均值或标准化过程访问 prices[t+1],就是未来数据进入信号。真实财务数据还要检查披露日,而不只是报告期。

成本测试

one_way_cost 分别设为 0、0.001 和 0.005,保存每组结果。成本不应只在最终收益上扣一次;它随仓位变化发生。换手高的规则可能在低成本假设下看似可行,稍微提高成本就失效。

参数搜索测试

如果继续测试 2 日、3 日、4 日直到找到最好结果,要把测试总数和全部结果一起记录,并预留独立样本外。Lo 与 MacKinlay 的NBER 论文说明数据窥探会严重扭曲检验;Bailey 等人的回测过拟合研究专门讨论大量搜索造成的样本外退化。

缺失和异常测试

把一个价格替换成 None,代码目前会失败。这是有价值的:它迫使研究者先定义缺失政策。真实数据中还要测试停牌、退市、涨跌停、复权事件、重复行和时区错位,不应默认前值填充。

换成真实数据前还差什么

点时数据与历史成分

使用当时可得的数据,而不是今天数据库中最终修订的值。财务字段以披露日控制可得性;指数和标的池保留历史成分及退市证券;公司行动与复权方法固定版本。

样本分离

样本内用于形成规则,验证集只做有限选择,样本外只在最终运行。反复查看样本外并调参后,它已经成为训练过程的一部分。应记录每次实验,而不是只保留最佳一次。

现实成交

说明信号何时可得、订单何时提交、用哪一档价格、未成交如何处理。加入佣金、税费、买卖价差、滑点、市场冲击、容量、最小申报单位、停牌和涨跌停。不同市场与产品的规则不能共用一个默认值。

基准和压力测试

与空仓、持有或更简单规则比较;改变成本、执行延迟、相邻参数与市场阶段。一个只在单一参数、单一时期成立的结果不能被概括成“有效策略”。

回测与程序化交易的监管边界

历史研究不等于真实下单。证监会程序化交易管理规定发布说明说明,程序化交易是通过计算机程序自动生成或者下达交易指令的行为。上交所实施细则进一步列出报告、交易软件版本、指令速率、风险监控等要求。

准备进入实盘前,应由相应券商、机构合规和专业人员确认适用规则;一段回测代码或研究页面不构成完成合规准备。

Bastix 没有统一回测引擎

Bastix 当前没有现成统一回测引擎。用户只能在受限代码工具中自行组织研究计算;自然语言策略结构化为 Beta,输出是研究与策略骨架,不是可直接执行算法。内置能力也没有券商连接和真实下单。1

因此本页 CTA 是“复制协议并独立复算”,不是“进入 Bastix 一键回测”。Bastix 可以帮助整理假设、数据清单和复核问题,但结果、代码和市场适用性仍由研究者负责。

下一步先原样运行合成例子,逐项完成前视、成本、参数搜索和缺失测试;全部结果与修改记录一致后,再把输入替换成授权的点时数据。需要生成规则草稿时,先使用AI 生成交易策略验收方法;想把回测放进更完整的量化研究流程,可参考量化交易研究指南

事实脚注

Footnotes

  1. Bastix《公开产品事实登记》0.1.0(取证日期 2026-08-14):“回测引擎”为 unsupported;“自然语言策略结构化”为 beta;“券商连接与真实下单”为 unsupported。相关市场数据链路也有覆盖、许可、延迟和修订边界。