如何为按symbol和date排序的DataFrame添加独立交易编号列
为交易订单分配独立交易编号
给定一个已按symbol和date排序的DataFrame,需要新增一列用于标识每笔独立交易。每笔独立交易指从**开仓(position opened)到平仓(position closed)**的一组买卖(buy/sell)订单,未平仓的交易也需要分配对应的交易编号。
输入数据
原始交易数据(带开平仓注释):
time symbol side price size 08-19-2021 AAPL buy 150 1 ----> position opened here 08-20-2021 AAPL buy 100 1 08-21-2021 AAPL buy 200 1 08-22-2021 AAPL sell 300 1 08-23-2021 AAPL sell 350 0.5 08-24-2021 AAPL sell 400 1.5 ----> position closed here 08-25-2021 AAPL buy 150 2 -----> position opened here 08-26-2021 AAPL sell 100 2 ----> position closed here 08-27-2021 AAPL buy 100 2 ---> position opened here 08-28-2021 AAPL sell 150 1.5 08-29-2021 AAPL buy 100 0.5 08-29-2021 AAPL sell 50 0.5 08-29-2021 AAPL sell 50 0.5 ---> position closed here 08-29-2021 AAPL buy 100 1 ----> position opened here 08-29-2021 AAPL sell 50 0.5 ---> position still open here
预期输出
新增
trade #列后的结果:
time symbol side price size trade # 08-19-2021 AAPL buy 150 1 0 08-20-2021 AAPL buy 100 1 0 08-21-2021 AAPL buy 200 1 0 08-22-2021 AAPL sell 300 1 0 08-23-2021 AAPL sell 350 0.5 0 08-24-2021 AAPL sell 400 1.5 0 ------------------------------- 08-25-2021 AAPL buy 150 2 1 08-27-2021 AAPL sell 100 2 1 ------------------------------- 08-28-2021 AAPL buy 100 2 2 08-29-2021 AAPL sell 150 1.5 2 08-29-2021 AAPL buy 100 0.5 2 08-29-2021 AAPL sell 50 0.5 2 08-29-2021 AAPL sell 50 0.5 2 ------------------------------ 08-29-2021 AAPL buy 100 1 3 08-29-2021 AAPL sell 50 0.5 3
最后一笔交易尚未平仓,仍需为其分配交易编号。
输入DataFrame构造代码
import pandas as pd df = pd.DataFrame.from_dict({ 'symbol': ['AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL'], 'side': ['buy', 'buy', 'buy', 'sell', 'sell', 'sell', 'buy', 'sell', 'buy', 'sell', 'buy', 'sell', 'sell', 'buy', 'sell'], 'size': [1,1,1,1,0.5,1.5,2,2,2,1.5, 0.5, 0.5, 0.5, 1, 0.5] })
解决方案
核心思路
- 计算每笔订单的持仓变化:
buy为正增量,sell为负增量 - 计算累计持仓,跟踪当前持仓状态
- 识别开仓信号:当累计持仓从0变为正数时,标记为新交易的起点
- 基于开仓信号的累计求和,生成唯一的交易编号
代码实现
import pandas as pd # 构造输入DataFrame df = pd.DataFrame.from_dict({ 'symbol': ['AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL', 'AAPL'], 'side': ['buy', 'buy', 'buy', 'sell', 'sell', 'sell', 'buy', 'sell', 'buy', 'sell', 'buy', 'sell', 'sell', 'buy', 'sell'], 'size': [1,1,1,1,0.5,1.5,2,2,2,1.5, 0.5, 0.5, 0.5, 1, 0.5] }) # 1. 计算每笔订单的持仓变化量 df['position_change'] = df.apply(lambda x: x['size'] if x['side'] == 'buy' else -x['size'], axis=1) # 2. 计算累计持仓 df['cum_position'] = df['position_change'].cumsum() # 3. 标记新交易的开仓点:前一行持仓为0,当前持仓转为正数 df['is_new_trade'] = (df['cum_position'] > 0) & (df['cum_position'].shift(1).fillna(0) == 0) # 4. 生成交易编号 df['trade #'] = df['is_new_trade'].cumsum() - 1 # 查看最终结果(按需保留或删除中间列) print(df[['symbol', 'side', 'size', 'trade #']])
结果验证
运行代码后,生成的trade #列与预期输出完全匹配,未平仓的最后一笔交易也被正确分配了编号3。
内容的提问来源于stack exchange,提问作者user2512443
相关产品推荐
相关产品推荐

