如何在Pandas中计算当前时间15秒后的股票未来收益?
问题描述
我有一个存储股票价格和时间的pandas DataFrame,time列类型为pd.datetime。示例代码如下:
import pandas as pd df = pd.DataFrame([['2022-09-01 09:33:00', 100.], ['2022-09-01 09:33:14', 101.], ['2022-09-01 09:33:16', 99.4], ['2022-09-01 09:33:30', 100.9]], columns=['time', 'price']) df['time'] = pd.to_datetime(df['time'])
初始DataFrame输出:
time price 0 2022-09-01 09:33:00 100.0 1 2022-09-01 09:33:14 101.0 2 2022-09-01 09:33:16 99.4 3 2022-09-01 09:33:30 100.9
需要计算当前时间15秒后第一个价格与当前价格的差值(即未来收益),期望结果如下:
time price return 0 2022-09-01 09:33:00 100.0 -0.6 // 未来价格为99.4,间隔16秒 1 2022-09-01 09:33:14 101.0 -0.1 // 未来价格为100.9,间隔16秒 2 2022-09-01 09:33:16 99.4 NaN 3 2022-09-01 09:33:30 100.9 NaN
解决方案
方法1:使用pd.merge_asof(推荐)
merge_asof专门用于时间序列的近似匹配,适合查找后续第一个符合时间条件的记录:
# 1. 生成每个时间点加15秒的目标时间列 df['future_time'] = df['time'] + pd.Timedelta(seconds=15) # 2. 准备用于匹配的右表,仅保留时间和价格列并重命名价格列 right_df = df[['time', 'price']].rename(columns={'price': 'future_price'}) # 3. 左连接,按forward方向匹配第一个大于等于目标时间的价格 result = pd.merge_asof(df, right_df, left_on='future_time', right_on='time', direction='forward') # 4. 计算收益并清理临时列 result['return'] = result['future_price'] - result['price'] result = result.drop(columns=['future_time', 'time_y']).rename(columns={'time_x': 'time'}) print(result)
输出结果:
time price future_price return 0 2022-09-01 09:33:00 100.0 99.4 -0.6 1 2022-09-01 09:33:14 101.0 100.9 -0.1 2 2022-09-01 09:33:16 99.4 NaN NaN 3 2022-09-01 09:33:30 100.9 NaN NaN
方法2:使用searchsorted
利用numpy的searchsorted找到目标时间在原时间列中的插入位置,再对应提取价格:
# 计算每个时间点加15秒后的目标时间 target_times = df['time'] + pd.Timedelta(seconds=15) # 找到每个目标时间在原时间列中的插入索引 indices = df['time'].searchsorted(target_times, side='left') # 根据索引获取未来价格,超出数据范围的设为NaN future_prices = df['price'].reindex(indices).where(indices < len(df)) # 计算收益 df['return'] = future_prices - df['price'] print(df)
输出结果与期望完全一致:
time price return 0 2022-09-01 09:33:00 100.0 -0.6 1 2022-09-01 09:33:14 101.0 -0.1 2 2022-09-01 09:33:16 99.4 NaN 3 2022-09-01 09:33:30 100.9 NaN
注意:两种方法都要求原DataFrame的
time列是升序排列的,如果数据无序,需先执行df = df.sort_values('time').reset_index(drop=True)。
内容的提问来源于stack exchange,提问作者nothingisme
相关产品推荐
相关产品推荐

