Pandas循环计算问题:基于前一行调整交易仓位控制风险
交易策略回测中依赖前序结果的Pandas递推计算解决方案
问题背景
在交易策略回测场景中,需要对Pandas DataFrame中的仓位进行动态调整:当计算出的risk超过max_risk时,调整Trade size,且后续行的计算必须使用上一行更新后的Trade size。普通向量化列操作无法处理这种递推依赖,导致当前代码计算结果不准确。
初始数据
| Trade Open | Trade number | Trade size | stop | close | risk | max risk |
|---|---|---|---|---|---|---|
| TRUE | 1 | 100% | 80 | 100 | 20.00% | 20% |
| 1 | 100% | 80 | 120 | 33.33% | 20% | |
| 1 | 100% | 80 | 140 | 42.86% | 20% | |
| 1 | 100% | 80 | 160 | 50.00% | 20% |
期望结果
| Trade Open | Trade number | Trade size | stop | close | risk | max risk | Reduction boolean | Reduction |
|---|---|---|---|---|---|---|---|---|
| TRUE | 1 | 100% | 80 | 100 | 20.00% | 20% | FALSE | 0% |
| 1 | 100% | 80 | 120 | 33.33% | 20% | TRUE | 40% | |
| 1 | 60% | 80 | 140 | 25.71% | 20% | TRUE | 22% | |
| 1 | 46.8% | 80 | 160 | 23.40% | 20% | TRUE | 15% |
当前错误代码
d = {'Trade Open': [True, False, False, False,], 'Trade number': [1]*4, 'Trade_size': [100]*4, 'close':[100,120,140,160],'stop': [80]*4, 'max_risk': [20]*4} df = pd.DataFrame(data=d) df['risk'] = (df.close - df.stop)/ df.close * df.Trade_size df['reduction_boolean'] = df.risk > df.max_risk df['reduction'] = 0 df.loc[df['reduction_boolean'], 'reduction'] = 1 - (df.max_risk / df.risk) df.loc[df['reduction_boolean'].shift() == True, 'Trade_size'] = df.Trade_size * (1-df.reduction.shift()) df
解决方案
由于Trade size的更新依赖上一行的计算结果,必须采用分组逐行迭代的方式处理,确保每一步的仓位调整都能传递到下一行。代码如下:
import pandas as pd # 初始化数据 d = { 'Trade Open': [True, False, False, False], 'Trade number': [1]*4, 'Trade_size': [100]*4, 'close': [100, 120, 140, 160], 'stop': [80]*4, 'max_risk': [20]*4 } df = pd.DataFrame(data=d) # 初始化新增列 df['risk'] = 0.0 df['reduction_boolean'] = False df['reduction'] = 0.0 # 按交易编号分组,逐组处理递推计算 for trade_num, group in df.groupby('Trade number'): indices = group.index # 初始化当前交易的仓位大小(取第一行初始值) current_size = df.loc[indices[0], 'Trade_size'] for i in indices: # 计算当前risk risk_val = (df.loc[i, 'close'] - df.loc[i, 'stop']) / df.loc[i, 'close'] * current_size df.loc[i, 'risk'] = round(risk_val, 2) # 判断是否需要调仓 if risk_val > df.loc[i, 'max_risk']: df.loc[i, 'reduction_boolean'] = True # 计算调仓比例 reduction_val = 1 - (df.loc[i, 'max_risk'] / risk_val) df.loc[i, 'reduction'] = round(reduction_val * 100, 1) # 更新下一行要用的仓位 current_size = current_size * (1 - reduction_val) else: df.loc[i, 'reduction_boolean'] = False df.loc[i, 'reduction'] = 0.0 # 无调仓,保持当前仓位 current_size = df.loc[i, 'Trade_size'] # 将调整后的仓位写回DataFrame # 第一行保持初始值,后续行用上一行调整后的值 df.loc[indices[0], 'Trade_size'] = 100 for idx in range(1, len(indices)): prev_idx = indices[idx-1] df.loc[indices[idx], 'Trade_size'] = round(df.loc[prev_idx, 'Trade_size'] * (1 - df.loc[prev_idx, 'reduction']/100), 1) # 格式化百分比显示 df['Trade_size'] = df['Trade_size'].astype(str) + '%' df['risk'] = df['risk'].astype(str) + '%' df['max_risk'] = df['max_risk'].astype(str) + '%' df['reduction'] = df['reduction'].astype(str) + '%' print(df)
代码说明
- 分组处理:按
Trade number分组,确保每个独立交易的计算逻辑互不干扰; - 递推变量维护:用
current_size保存上一行调整后的仓位,逐行传递更新; - 逐行计算:依次计算
risk、判断调仓条件、更新仓位和相关列; - 格式调整:最后将数值转为百分比格式,与期望结果一致。
内容的提问来源于stack exchange,提问作者James Cabourne
相关产品推荐
相关产品推荐

