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

如何用numpy.where实现列依赖的交易信号计算(无需循环)

问题描述

我有一个仅含z_score列的小型DataFrame,需要生成sell、position、short_exit三列。

原始数据如下:

z_score
2024-05-23 21:00:00  0.639482
2024-05-23 22:00:00  1.133366
2024-05-23 23:00:00 -0.267677
2024-05-24 00:00:00  0.681130
2024-05-24 01:00:00  2.283615
2024-05-24 02:00:00  1.916469
2024-05-24 03:00:00  2.284099
2024-05-24 04:00:00  2.283456
2024-05-24 05:00:00  2.699485
2024-05-24 06:00:00  2.393399
2024-05-24 07:00:00  1.871835
2024-05-24 08:00:00  1.824887

交易规则:

  • 当z_score大于2且当前无持仓(position为0)时,sell列设为1,position列设为1(表示持仓)并保持该状态
  • 直到z_score低于0时平仓,此时short_exit列设为1,position列重置为0

原代码问题

我尝试用以下代码实现但未成功,position列出现不应为0的错误值:

import pandas as pd
import numpy as np

df = pd.read_excel("gate.xlsx", sheet_name="Sheet3")
# 初始化sell、positions、short_exit列为0
df['sell'] = 0
df['positions'] = 0
df['short_exit'] = 0

df['sell'] = np.where((df['z_score'] > 2) & (df['positions'].shift(1) == 0), 1, 0)
df['positions'] = np.where(((df['sell'] == 1) | (df['positions'].shift(1) == 1)) & (df['short_exit'] == 0), 1, df['positions'])
df['short_exit'] = np.where((df['z_score'] < 0) & (df['positions'] == 1), 1 ,0)

# 输出结果DataFrame
print(df)

同时有疑问:有人说这类计算需要递归,无法用numpy实现,请问是否真的如此?


解决方案

你的代码问题在于列的计算顺序和依赖关系处理错误:numpy的np.where是向量化计算,会一次性对整列求值,无法处理逐行的状态依赖(比如position的当前值依赖上一行的状态,而short_exit又依赖当前行的position)。

方案1:逐行迭代(直观易维护)

因为持仓状态是累计依赖的,逐行迭代是最直接的实现方式,逻辑清晰不易出错:

import pandas as pd

df = pd.read_excel("gate.xlsx", sheet_name="Sheet3")
# 初始化列
df['sell'] = 0
df['position'] = 0
df['short_exit'] = 0

# 记录当前持仓状态
current_position = 0

for idx, row in df.iterrows():
    if current_position == 0:
        # 无持仓时检查开仓条件
        if row['z_score'] > 2:
            df.loc[idx, 'sell'] = 1
            current_position = 1
            df.loc[idx, 'position'] = 1
    else:
        # 有持仓时保持状态,检查平仓条件
        df.loc[idx, 'position'] = 1
        if row['z_score'] < 0:
            df.loc[idx, 'short_exit'] = 1
            current_position = 0

print(df)

方案2:向量化实现(高效无迭代)

如果想避免逐行迭代提升效率,可以用pandas的cumsum和布尔掩码构造持仓区间,实现无迭代的向量化计算:

import pandas as pd

df = pd.read_excel("gate.xlsx", sheet_name="Sheet3")

# 1. 标记初始开仓信号:z_score>2且之前未进入持仓
df['sell'] = (df['z_score'] > 2) & (df['z_score'].shift(1).le(2).fillna(True))

# 2. 计算持仓状态:用开仓与平仓信号的累计差判断是否持仓
open_signals = df['sell'].cumsum()
close_signals = df['z_score'].lt(0).cumsum()
df['position'] = ((open_signals - close_signals) > 0).astype(int)

# 3. 标记平仓信号:z_score<0且上一行处于持仓状态
df['short_exit'] = (df['z_score'] < 0) & (df['position'].shift(1) == 1)
df['short_exit'] = df['short_exit'].astype(int)

# 修正sell列:仅保留无持仓时的有效开仓信号
df['sell'] = df['sell'] & (df['position'].shift(1).fillna(0) == 0)
df['sell'] = df['sell'].astype(int)

print(df)

关于递归的疑问

这类计算不需要递归,但确实无法用单纯的numpy向量化直接实现——因为numpy的向量化操作是无状态的,无法处理“当前值依赖上一行结果”的累计状态。不过pandas提供了cumsum、shift等工具,可以通过构造状态区间的方式实现向量化计算,避免逐行迭代。

逐行迭代逻辑直观,但数据量大时效率较低;向量化方案效率更高,但逻辑稍复杂,可以根据数据规模选择合适的方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 09:23:15