You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python向量化回测中空头收益率计算错误修正

问题描述

我持有某交易标的的DataFrame数据集,包含position_signal(持仓信号)和close(收盘价)两个字段,每一行对应一个固定时间步(分钟、小时等周期)的行情数据。我需要运行向量化回测,计算每个时间点的累计组合收益率,覆盖多头持仓、空头持仓、空仓三种状态,三种状态对应的position_signal取值分别为1、-1、0。

已尝试方案

该问题看似实现简单,我已尝试过多种编写方式。目前网上有大量教程资料声称实现了正确的向量化回测逻辑,但这些方案普遍存在两类缺陷:要么错误设定持仓期间的收益累计规则(简单将各周期收益率连乘,不符合固定持仓的实际收益计算逻辑),要么空头收益率的计算逻辑错误。

这类教程的核心实现代码基本如下:

df['log_returns'] = np.log(df['close']) - np.log(df['close'].shift(1))
df['strategy_returns'] = df['position_signal'] * df['log_returns']
df['cumulative_ret'] = df['strategy_returns'].cumsum().apply(np.exp) 

这套逻辑计算多头持仓收益时结果正确,但计算空头持仓收益时会出现明显偏差,核心错误在于其默认空头收益率是等规模多头收益率的相反数,该逻辑完全不符合实际交易的收益计算规则。

示例说明

举一个简单的算例:假设回测中包含两笔交易,第一笔为多头持仓,入场价格1美元,出场价格2美元;第二笔为空头持仓,入场价格2美元,出场价格1美元。正确的收益计算结果为:第一笔多头交易收益率100%,第二笔空头交易收益率50%。若初始资金为100美元,第一笔交易后资金增长至200美元,第二笔交易后资金增长至300美元,最终累计收益率为300%。

但上述教程给出的代码可以正确计算多头收益,却会将第二笔空头交易的收益率误算为100%(直接取多头持仓-100%收益率的相反数),导致最终结果错误。

问题验证代码

以下代码可复现该错误:需要说明的是,代码中在position_signal首次出现1/-1的下一个时间步才正式持仓,相当于对position_signal做了1位偏移以避免未来函数,该处理属于细节设定,不影响核心收益逻辑的正确性。

import pandas as pd
import numpy as np

df = pd.DataFrame([[0.0, 1.0],
                   [0.0, 1.2],
                   [0.0, 1.50],
                   [0.0, 1],
                   [1.0, 1.2], # 本时间步开盘入场做多,开盘价等于上一步收盘价1.0美元
                   [1.0, 1.3],
                   [1.0, 2.0], # 本时间步收盘平仓,平仓价2.0美元
                   [0.0, 1.7],
                   [0.0, 2],
                   [-1.0, 1.798], # 本时间步开盘入场做空,开盘价等于上一步收盘价2.0美元
                   [-1.0, 0.50],
                   [-1.0, 1.3],
                   [-1.0, 1], # 本时间步收盘平仓,平仓价1.0美元
                   [0.0, 1.5]],
                   columns=['position_signal','close'])

df['log_returns'] = np.log(df.close) - np.log(df.close.shift(1))
df['strategy_returns'] = df.log_returns * df.position_signal
df['cumulative_returns'] = df.strategy_returns.cumsum().apply(np.exp)
print(df)
代码运行输出
position_signal  close  log_returns  strategy_returns  cumulative_returns
0               0.0  1.000          NaN               NaN                 NaN
1               0.0  1.200     0.182322          0.000000            1.000000
2               0.0  1.500     0.223144          0.000000            1.000000
3               0.0  1.000    -0.405465         -0.000000            1.000000
4               1.0  1.200     0.182322          0.182322            1.200000
5               1.0  1.300     0.080043          0.080043            1.300000
6               1.0  2.000     0.430783          0.430783            2.000000
7               0.0  1.700    -0.162519         -0.000000            2.000000
8               0.0  2.000     0.162519          0.000000            2.000000
9              -1.0  1.798    -0.106472          0.106472            2.224694
10             -1.0  0.500    -1.279822          1.279822            8.000000
11             -1.0  1.300     0.955511         -0.955511            3.076923
12             -1.0  1.000    -0.262364          0.262364            4.000000
13              0.0  1.500     0.405465          0.000000            4.000000

从输出结果可见,代码计算的最终累计收益为4.0(即400%),和正确结果3.0(300%)存在明显偏差。


其他方案的局限性

  • 若忽略中间价格tick,仅保留开多、平多、开空、平空四个交易节点的行数据,通过持仓信号掩码计算单笔交易收益后再做cumprod可以得到正确结果,但该方法无法输出持仓期间每个时间步的组合价值,无法满足逐时点净值观测的需求,因此不适用。
  • 也有方案将多头和空头的损益分开计算,但该方法未考虑历史盈亏对后续交易购买力的影响(例如一笔多头交易亏损50%后,下一笔交易盈利50%并不能使净值回到初始水平),逻辑存在本质缺陷。
  • 采用非向量化的逐行遍历方式实现回测虽然逻辑容易写对,但运行速度过慢,无法满足大规模回测的性能要求。

现寻求可正确计算逐时点多空组合收益的高效向量化实现方案。

内容的提问来源于stack exchange,提问作者Joe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 02:24:21