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

如何用Pandas Dataframe计算策略总盈亏(PnL)?持仓不重复累计

策略总盈亏(PnL)计算问题解决

问题背景

现有一份Pandas DataFrame,close为收盘价,entry_prices为开仓时的收盘价;平仓后entry_prices变为NaN,直至再次开仓。需计算策略总盈亏(PnL),要求:

  • 持仓期间不重复累计盈亏(仅显示当前持仓浮盈+历史平仓总盈亏)
  • 回测时假设任何时刻仅持有1手仓位

原始DataFrame

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'close': [98, 101, 106, 107, 110, 111, 120, 123, 124, 123, 122, 123, 120, 121, 125],
    'entry_prices': [np.nan, 101.0, 101.0, 101.0, 101.0, 101.0, np.nan, np.nan, np.nan, 123.0, 123.0, 123.0, 123.0, np.nan, np.nan]
})

用户尝试的错误代码

df['pnl'] = np.where(df['entry_prices'].shift() == df['entry_prices'], df['close'] - df['entry_prices'], 0)

# Initialize strategy_pnl column
df['strategy_pnl'] = np.nan

# Calculate the cumulative sum of total P&L regardless of trading positions
cumulative_pnl = 0
for idx, row in df.iterrows():
    if not np.isnan(row['entry_prices']):
        pnl = row['close'] - row['entry_prices']
        cumulative_pnl += pnl
    df.at[idx, 'strategy_pnl'] = cumulative_pnl

这段代码的问题是持仓期间会重复累加每日浮盈,导致总盈亏计算混乱。

期望输出结果

close  entry_prices  Total_PNL
0      98           NaN          0
1     101         101.0          0
2     106         101.0          5
3     107         101.0          6
4     110         101.0          9
5     111         101.0         10
6     120           NaN         10
7     123           NaN         10
8     124           NaN         10
9     123         123.0         10
10    122         123.0          9
11    123         123.0          9
12    120         123.0          6
13    121           NaN          6
14    125           NaN          6

正确解决方案

核心思路:识别每笔交易的开平仓区间,仅在平仓时记录该笔交易的固定盈亏,持仓时显示当前浮盈加历史平仓累计盈亏。

# 1. 标记交易区间:对非NaN的entry_prices分组,NaN设为0
df['trade_group'] = df['entry_prices'].notna().cumsum()
df['trade_group'] = np.where(df['entry_prices'].isna(), 0, df['trade_group'])

# 2. 计算每笔交易的平仓盈亏(仅在平仓时刻记录该笔最终盈亏)
df['close_pnl'] = np.where(
    # 平仓条件:当前为NaN,前一行处于持仓状态
    df['entry_prices'].isna() & df['entry_prices'].shift().notna(),
    # 用平仓前最后收盘价减开仓价
    df['close'].shift() - df['entry_prices'].shift(),
    0
)

# 3. 计算历史平仓总盈亏的累计值
df['cum_close_pnl'] = df['close_pnl'].cumsum()

# 4. 计算当前持仓浮盈:持仓时用当前收盘价减开仓价,否则为0
df['holding_pnl'] = np.where(df['entry_prices'].notna(), df['close'] - df['entry_prices'], 0)

# 5. 总盈亏 = 历史平仓累计盈亏 + 当前持仓浮盈
df['Total_PNL'] = df['cum_close_pnl'] + df['holding_pnl']

# 处理初始值,填充为0并转为整数
df['Total_PNL'] = df['Total_PNL'].fillna(0).astype(int)

# 可选:删除中间辅助列
df = df.drop(['trade_group', 'close_pnl', 'cum_close_pnl', 'holding_pnl'], axis=1)

print(df)

运行后即可得到符合要求的结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 20:58:14