Python实现债券市场有效价差计算:时序数据合并与计算咨询
如何匹配交易前的报价并计算债券有效价差?
我来一步步帮你解决这个问题——核心就是给每笔交易匹配到它发生前最近的报价中点,然后套用公式计算有效价差。用Pandas的merge_asof函数就能完美解决时序匹配的问题,比自己写循环高效太多。
步骤1:准备并清洗数据
首先我们先把示例数据加载进来,然后统一时间格式(把日期和时间字段合并成完整的datetime类型,这样才能做时序比较),同时计算报价中点。
import pandas as pd # 加载示例报价数据 quote_data = pd.DataFrame({ 'Id': [1, 1, 2], 'BuyTime': ['09:00:20', '09:10:21', '09:11:22'], 'BuyPrice': [1005, 1020, 1032], 'Date': ['2010-01-01', '2010-01-01', '2010-01-02'], 'SellTime': ['09:00:10', '09:10:25', '09:11:19'], 'SellPrice': [1001, 1012, 1020] }) # 加载示例交易数据 trade_data = pd.DataFrame({ 'Id': [1, 1, 2], 'Time': ['09:00:21', '09:10:26', '09:11:23'], 'Date': ['2010-01-01', '2010-01-01', '2010-01-02'], 'Price': [1004, 1017, 1028] # 修正示例笔误:2028→1028 }) # 处理报价数据:合并日期和最新的报价时间(取买卖报价时间中较晚的),计算中点 quote_data['BuyDatetime'] = pd.to_datetime(quote_data['Date'] + ' ' + quote_data['BuyTime']) quote_data['SellDatetime'] = pd.to_datetime(quote_data['Date'] + ' ' + quote_data['SellTime']) quote_data['QuoteDatetime'] = quote_data[['BuyDatetime', 'SellDatetime']].max(axis=1) quote_data['MidQuote'] = (quote_data['BuyPrice'] + quote_data['SellPrice']) / 2.0 quote_clean = quote_data[['Id', 'Date', 'QuoteDatetime', 'MidQuote']] # 处理交易数据:合并日期和时间成完整datetime trade_data['TradeDatetime'] = pd.to_datetime(trade_data['Date'] + ' ' + trade_data['Time']) trade_clean = trade_data[['Id', 'Date', 'TradeDatetime', 'Price']]
步骤2:时序匹配交易与报价
这里用pd.merge_asof是关键——它专门用于按时间顺序匹配两个数据集,能高效找到每笔交易发生前最近的报价:
by=['Id', 'Date']:确保只匹配同一个债券(Id)、同一天的报价,避免跨品种/跨日期错误匹配direction='backward':指定只找交易时间之前的最近报价(t-ε时刻的报价)- 注意:必须先对两个数据集的时间列排序,
merge_asof要求输入是有序的
# 执行时序匹配 merged_data = pd.merge_asof( trade_clean.sort_values('TradeDatetime'), quote_clean.sort_values('QuoteDatetime'), by=['Id', 'Date'], left_on='TradeDatetime', right_on='QuoteDatetime', direction='backward' )
步骤3:计算有效价差
根据你给出的公式:
- 买入市价单(成交价格>报价中点):
2*(pt - mt) - 卖出市价单(成交价格<报价中点):
2*(mt - pt) - 若成交价格等于中点,有效价差为0
用apply函数就能轻松实现这个逻辑:
# 计算有效价差 merged_data['EffectiveSpread'] = merged_data.apply( lambda row: 2 * (row['Price'] - row['MidQuote']) if row['Price'] > row['MidQuote'] else 2 * (row['MidQuote'] - row['Price']) if row['Price'] < row['MidQuote'] else 0, axis=1 ) # 查看最终结果 print(merged_data[['Id', 'TradeDatetime', 'Price', 'MidQuote', 'EffectiveSpread']])
输出结果和你的示例完全一致:
Id TradeDatetime Price MidQuote EffectiveSpread 0 1 2010-01-01 09:00:21 1004 1003.0 2.0 1 1 2010-01-01 09:10:26 1017 1016.0 2.0 2 2 2010-01-02 09:11:23 1028 1026.0 4.0
注意事项
- 边界情况处理:如果某笔交易之前没有任何报价(比如当天第一笔交易),
merge_asof会让MidQuote为NaN,你可以根据需求用dropna()删除这些记录,或者用当天第一笔报价填充。 - 时间精度:如果你的数据有毫秒级精度,确保
datetime列保留足够的精度,避免匹配错误。 - 大数据量适配:
merge_asof是向量化操作,比循环处理快得多,即使是百万级别的数据也能高效运行。
内容的提问来源于stack exchange,提问作者ary
相关产品推荐
相关产品推荐

