非时间维度分桶:基于数量计算VWAP的Pandas/Numpy实现方法问询
简洁实现每50数量单位的VWAP计算
嘿,这个问题我太有共鸣了!之前用循环拆单个数量单位的方式处理,不仅代码臃肿,数据量大的时候慢得离谱。其实用 Pandas 结合 Numpy 的向量化操作就能高效解决,完全不用拆分成单个条目。下面是具体的实现思路和代码:
步骤1:构造测试数据
先把你给出的 DataFrame 构造出来,方便后续演示:
import pandas as pd import numpy as np df = pd.DataFrame({ 'price': [100, 102, 105, 99, 104, 103, 101], 'quantity': [20, 31, 25, 40, 10, 20, 55] })
步骤2:计算累积指标
先算出累积成交量和累积成交金额,这是后续分组计算的核心基础:
# 累积成交量 df['cum_qty'] = df['quantity'].cumsum() # 累积成交金额(价格×数量的累积和) df['cum_amt'] = (df['price'] * df['quantity']).cumsum()
步骤3:批量计算VWAP
核心思路是按每50单位的区间划分批次,通过搜索累积成交量的索引,快速定位每个批次覆盖的行,再计算该批次的总金额和总数量,最终得到VWAP:
# 生成所有批次的边界(0-50,50-100,...) max_total_qty = df['cum_qty'].iloc[-1] batch_bins = np.arange(0, max_total_qty + 50, 50) vwap_list = [] for start, end in zip(batch_bins[:-1], batch_bins[1:]): # 定位批次覆盖的起始和结束行索引 idx_start = df['cum_qty'].searchsorted(start, side='left') idx_end = df['cum_qty'].searchsorted(end, side='left') - 1 total_qty = 0 total_amt = 0 # 处理批次内的完整行 if idx_start <= idx_end: total_qty += df['quantity'].iloc[idx_start:idx_end+1].sum() total_amt += (df['price'] * df['quantity']).iloc[idx_start:idx_end+1].sum() # 处理起始行的部分成交量(当批次起始点不在累积量的节点上时) if idx_start > 0: prev_cum = df['cum_qty'].iloc[idx_start - 1] if start > prev_cum: partial_qty = start - prev_cum total_qty += partial_qty total_amt += df['price'].iloc[idx_start] * partial_qty # 处理结束行的部分成交量(当批次结束点不在累积量的节点上时) if idx_end < len(df) - 1: curr_cum = df['cum_qty'].iloc[idx_end] if end > curr_cum: partial_qty = end - curr_cum total_qty += partial_qty total_amt += df['price'].iloc[idx_end + 1] * partial_qty # 计算当前批次的VWAP(避免除以0的情况) if total_qty > 0: vwap = total_amt / total_qty vwap_list.append({ '批次区间': f'{start}-{end}单位', 'VWAP': round(vwap, 2), '实际成交量': total_qty }) # 转成DataFrame查看结果 vwap_result = pd.DataFrame(vwap_list) print(vwap_result)
结果说明
运行后会得到每个50单位批次的VWAP值,哪怕某一行的成交量跨了两个批次(比如第2行的31单位,前10单位属于第一个批次,后21单位属于第二个批次),代码也能自动拆分计算,完全不需要循环处理单个数量单位。如果最后一批的成交量不足50单位,代码也会正常计算VWAP,你可以根据需求决定是否保留这一批。
内容的提问来源于stack exchange,提问作者cJc
相关产品推荐
相关产品推荐

