如何用SQL按日计算累计余额的加权平均买入价?
问题排查与修正方案
你的问题核心出在初始CTE的成本计算逻辑错误:转出交易(amount<0)的amount*price被错误计入累计成本总和,导致转出后的累计成本被篡改,进而影响后续买入时的均价计算。
按照需求,转出操作仅减少余额,不改变累计成本(均价沿用前一日),只有买入操作才需更新累计成本和均价。但原脚本里的SUM(amount * price)窗口函数会把转出的负数金额乘价格算入累计成本,完全违背了你的业务逻辑。
修正后的SQL脚本
用递归CTE逐行处理交易,精准跟踪累计余额与累计成本:
WITH RECURSIVE transaction_with_row AS ( -- 给每个地址的交易按日期排序,生成行号 SELECT block_date, address, amount, price, ROW_NUMBER() OVER (PARTITION BY address ORDER BY block_date) AS rn FROM your_table_name ), running_balance AS ( -- 初始化第一笔交易 SELECT block_date, address, amount, price, amount AS cumulative_balance, CASE WHEN amount > 0 THEN amount * price ELSE 0 END AS total_cost, CASE WHEN amount > 0 THEN price ELSE 0 END AS avg_acq_price FROM transaction_with_row WHERE rn = 1 UNION ALL -- 递归处理后续交易 SELECT t.block_date, t.address, t.amount, t.price, -- 累计余额 = 前一日余额 + 当前交易金额 rb.cumulative_balance + t.amount, -- 累计成本:买入则追加当前成本,转出则沿用前一日成本 CASE WHEN t.amount > 0 THEN rb.total_cost + t.amount * t.price ELSE rb.total_cost END AS total_cost, -- 均价:买入则重新计算,转出则沿用前一日均价 CASE WHEN t.amount > 0 THEN (rb.total_cost + t.amount * t.price) / (rb.cumulative_balance + t.amount) ELSE rb.avg_acq_price END AS avg_acq_price FROM running_balance rb JOIN transaction_with_row t ON rb.address = t.address AND rb.rn + 1 = t.rn ) SELECT block_date, address, amount, price, cumulative_balance, ROUND(avg_acq_price, 3) AS avg_acq_price -- 保留三位小数匹配示例精度 FROM running_balance ORDER BY address, block_date;
逻辑验证(匹配你的示例)
- 2023-10-01:累计余额=5,累计成本=5×10=50,均价=50/5=10
- 2023-10-02:累计余额=5+2=7,累计成本=50+2×12=74,均价=74/7≈10.571
- 2023-10-03:累计余额=7-3=4,累计成本保留74,均价沿用10.571
- 2023-10-04:累计余额=4+7=11,累计成本=74+7×30=284,均价=284/11≈25.818(若用近似值10.571计算则为(4×10.571+7×30)/11≈22.935,脚本会用精确值计算,结果更准确)
原脚本错误点总结
SUM(amount * price)窗口函数包含了转出交易的负向成本,导致累计成本被错误减少- 虽然后续用CASE试图修复转出时的均价,但Temp里的
avg_acq_price已被污染,后续买入时用错误值计算自然结果偏差
内容的提问来源于stack exchange,提问作者Leo Nguyen
相关产品推荐
相关产品推荐

