← 返回博客列表

量化投资从入门到精通

【量化投资从入门到精通 #26】把想法写成可回测的代码策略工程化骨架

2026年08月22日 16:56 · 麦蕊智数 MyData

策略层收官。前面 6 篇讲了 6 类策略思想,这篇讲怎么把任何一个想法,变成能跑、能测、能交接的代码

一、这个方法解决什么投资问题

大多数人的策略是这样的:"我觉得放量突破 20 日线可以买。" 然后打开行情软件手动翻。 问题在于:这句话无法被验证。涨的时候你记得,跌的时候你忘了。

工程化要解决的就是一件事:把主观描述变成一段确定性的代码,让历史来投票。

二、核心思想:三段分离

一个可维护的策略骨架,永远只有三块,而且必须互相隔离

模块 职责 铁律
signal(kl, i) 第 i 根 K 线,输出仓位 0/1 只能读 t ≤ i 的数据
backtest(kl) 遍历、撮合、算净值 决策与成交错开一根 K 线
calc_metrics(eq) 收益/回撤/夏普 只吃净值曲线,不碰行情

三段分离的价值:换策略只改 signal(),回测和绩效永远复用;出了问题也能快速定位是"想法错了"还是"回测写错了"。

三、实操演示

def signal(kl, i):
    """第 i 根 K 线,返回 0/1 仓位。所有'取数只用 t<=i'。"""
    if i < 20: return 0
    ma20 = sum(r["close"] for r in kl[i-20:i]) / 20
    return 1 if kl[i]["close"] > ma20 else 0

def backtest(kl):
    # 关键:第 i 根的仓位由"截至 i-1 的已知数据"决定,应用到第 i 根收益
    pos = [0] * len(kl)
    for i in range(1, len(kl)):
        pos[i] = signal(kl, i - 1)
    equity = [1.0]
    for i in range(1, len(kl)):
        day = kl[i]["close"] / kl[i-1]["close"] - 1
        equity.append(equity[-1] * (1 + pos[i] * day))
    return equity

真实输出(2026-08-06,600519): 骨架示例(站上 20 日线持有,当日决策次日生效)累计 −9.54%、夏普 −0.66

四、结果解读

注意这个负收益——它恰恰是这篇文章最有价值的地方。

修 bug 前,同一段逻辑跑出 +41.49%。 原因是第一版写成了 pos[i] = signal(kl, i):用第 i 天的收盘价决定第 i 天的仓位。收盘价出来的时候,当天已经收盘了,你根本买不进去。这就是 #04 讲过的前视偏差

改成 pos[i] = signal(kl, i-1)(昨天收盘决策、今天持有),收益从 +41.49% 直接掉到 −9.54%。一行下标之差,51 个百分点。

结论:骨架不是"代码整洁"这种审美问题,而是结构本身决定了你会不会作弊。三段分离 + 决策/成交错位,是从架构层面堵死前视偏差。

五、常见陷阱

  • signal() 里偷看未来:出现 kl[i+1]max(closes)、全样本 mean() 都是红灯。
  • 决策与成交同一根 K 线:最高频的错误,收益虚高几十个点。
  • 绩效函数里混行情:一旦 calc_metrics 读了原始 K 线,就无法用合成净值做单元测试。
  • 参数写死在函数体:换周期要改源码,无法做 #20 那样的敏感性扫描。

六、小结 + 下篇预告

策略工程化 = signal() + backtest() + calc_metrics() 三段分离,决策与成交错一根 K 线。这套骨架配上统一回测引擎,本系列所有策略都用同一个引擎跑出来。

策略层(#20–#26)到此收官。下篇进入评价与风控层 #27:样本外与前推验证——回测好看不算数,怎么证明策略不是拟合出来的。

免责声明

本文为量化方法教学,标的为示例,不构成投资建议,不承诺收益。投资有风险,入市需谨慎。

标签: 股票行情API
QQ 客服 3826425416 咨询时请提供证书号或订单号,便于快速处理
咨询