如何基于向量化方法计算带交易信号的DataFrame的PnL
无循环计算配对交易PnL的向量化方案
问题说明
给定含价格与开平仓信号的DataFrame,需无循环计算配对交易的每日PnL:
Entry (short):做空A、做多B;Entry (long):做多A、做空BExit (short)/Exit (long)对应平仓对应头寸,信号时序有序,平仓均晚于开仓- PnL规则:
- 空头区间:
(B.pct_change() - A.pct_change())/2 - 多头区间:
(-B.pct_change() + A.pct_change())/2
- 空头区间:
开平仓信号样例
price_df[price_df["Signal"].str.contains("E")] A B A/B Z score Signal 2021-04-19 4926.1 148.2251 2.187012 Entry (short) 2021-05-31 4357.7 159.8565 0.030637 Exit (short) 2022-01-06 4658.9 137.4595 2.139689 Entry (short) 2022-02-07 3624.1 123.2928 -0.018995 Exit (short)
头寸区间样例(开平仓间标记为-1/1)
A B A/B Z score Signal 2021-04-19 4926.1 148.2251 2.187012 Entry (short) 2021-04-20 4726.9 145.8136 1.880473 -1 2021-04-21 4488.9 140.3698 1.715539 -1 ... 2021-05-27 4333.4 157.0219 0.165915 -1 2021-05-28 4440.3 157.4703 0.417588 -1 2021-05-31 4357.7 159.8565 0.030637 Exit (short)
向量化实现步骤
1. 生成头寸标记列
通过ffill()向前填充,实现开仓到平仓区间内的头寸持续标记:
# 初始化头寸列为0 price_df['position'] = 0 # 映射开平仓信号到头寸值 price_df.loc[price_df['Signal'] == 'Entry (short)', 'position'] = -1 price_df.loc[price_df['Signal'] == 'Exit (short)', 'position'] = 0 price_df.loc[price_df['Signal'] == 'Entry (long)', 'position'] = 1 price_df.loc[price_df['Signal'] == 'Exit (long)', 'position'] = 0 # 向前填充,让开仓后到平仓前保持头寸方向 price_df['position'] = price_df['position'].ffill()
2. 计算每日PnL
利用向量运算直接计算,无需循环:
# 计算A、B的日收益率 price_df['A_pct'] = price_df['A'].pct_change() price_df['B_pct'] = price_df['B'].pct_change() # 根据头寸方向计算每日PnL # 多头头寸(1)对应(A_pct - B_pct)/2,空头(-1)对应(B_pct - A_pct)/2,无头寸(0)为0 price_df['PnL'] = price_df['position'] * (price_df['A_pct'] - price_df['B_pct']) / 2
3. 可选:处理开仓日NaN与累计盈亏
- 开仓当日的
pct_change()为NaN,可填充为0:
price_df['PnL'] = price_df['PnL'].fillna(0)
- 计算累计盈亏:
price_df['cum_PnL'] = price_df['PnL'].cumsum()
内容的提问来源于stack exchange,提问作者Anonymous
相关产品推荐
相关产品推荐

