diff --git a/项目文档/数据库/排查SQL/互换分红损益_数据导出与验证.sql b/项目文档/数据库/排查SQL/互换分红损益_数据导出与验证.sql index b6eb9c0c..358c67a0 100644 --- a/项目文档/数据库/排查SQL/互换分红损益_数据导出与验证.sql +++ b/项目文档/数据库/排查SQL/互换分红损益_数据导出与验证.sql @@ -1,3 +1,21 @@ + +SELECT sfe.SwapTradeId, + MAX(sfe.SwapTradeNo) AS SwapTradeNo, + SUM(sfe.DividendIn) AS 分红合计, + SUM(sfe.MarkClosePnl) AS 盯市合计, + -- 关键:必须有 eod 归档才算"走完EOD的有效样本" + (SELECT COUNT(*) FROM eod_swap_position esp + WHERE esp.SwapTradeId = sfe.SwapTradeId) AS eod持仓快照数, + (SELECT COUNT(*) FROM eod_swap es + WHERE es.SwapTradeId = sfe.SwapTradeId) AS eod汇总数 +FROM swap_flow_event sfe +WHERE sfe.EventType IN (3,4) AND sfe.DividendIn <> 0 AND sfe.DataState = 100 +GROUP BY sfe.SwapTradeId +HAVING eod持仓快照数 > 0 AND eod汇总数 > 0 -- ← 这道过滤保证种子完整 +ORDER BY ABS(SUM(sfe.DividendIn)) DESC, MAX(sfe.SwapTradeNo) DESC; + + + -- ============================================================================ -- 互换分红损益:数据导出与重复计算验证 SQL 工具箱 -- ---------------------------------------------------------------------------- @@ -235,6 +253,120 @@ WHERE sfe.SwapTradeId = @TargetTradeId ORDER BY sfe.EventDate; +-- ============================================================================ +-- 第 2.5 步:分红被计算两次的完整证明(含事件/价格/费用/付息明细) +-- ============================================================================ +-- 本节用 4 个查询把"分红重复计算"的证据链完整还原: +-- 段1事件明细:每条平仓/互换事件,把 MarkClosePnl 拆成 价差+费+分红 三成分。 +-- 若"价差"残差~0 且 DividendIn<>0,证明 MarkClosePnl 里装的就是分红。 +-- 段2 EOD逐日:盯市列(TdCloseMtmPnl) 与 分红列(TdCloseDividend) 同日出现等额分红。 +-- 段3 累计对照:盯市列累计 RealizedMtmPnL 含了分红成分,分红列累计 RealizedDividend 又含一份。 +-- 段4 一句话结论:重复金额 = 盯市列里的分红成分(按 PositionId 汇总避免双向腿抵消)。 +-- +-- 已用 golden 数据(1875纯分红型重复302400、1891混合型重复-18.66)校验本 SQL 结果正确。 + +SET @TargetTradeId := 1875; -- 替换为实际样本(1875=纯分红型 / 1891=混合型) + +-- 段1 事件明细拆解:MarkClosePnl = 价差 + 费(CloseFee) + 分红(DividendIn) +-- 价差残差 = MarkClosePnl - DividendIn - CloseFee +-- 纯分红型:价差残差~0(MarkClosePnl 全是分红) +-- 混合型 :价差残差<>0(MarkClosePnl 含真实价差 + 少量分红) +SELECT sfe.id, + sfe.EventDate, + CASE sfe.EventType WHEN 1 THEN '开仓' WHEN 2 THEN '平仓' + WHEN 3 THEN '互换' WHEN 4 THEN '自动互换' END AS 事件类型, + sfe.PositionId, + sfe.UnderlyingCode, + sfe.Quantity, + sfe.TradingAmountAvg AS 成交均价不含费, + sfe.TradingAmountFeeAvg AS 含费均价, + sfe.TradingAmountNetAvg AS 成交净价不含费, + sfe.TradingAmountNetFeeAvg AS 成交净价含费, + sfe.TradingAmount AS 成交金额, + sfe.TradingFee AS 交易佣金, + sfe.TradingFeePending AS 待结算后付费用, + sfe.CloseFee AS 平仓费用_费成分, + sfe.DividendPending AS 待结算分红, + sfe.DividendIn AS 分红流入_分红成分, + sfe.MarkClosePnl AS 盯市盈亏_总额, + (sfe.MarkClosePnl - sfe.DividendIn - sfe.CloseFee) AS 价差残差, + CASE WHEN sfe.EventType IN (2,3,4) + AND ABS(sfe.MarkClosePnl - sfe.DividendIn - sfe.CloseFee) < 0.01 + AND sfe.DividendIn <> 0 + THEN '根因:价差~0->MarkClosePnl全是分红' + WHEN sfe.EventType IN (2,3,4) AND sfe.DividendIn <> 0 + THEN '混合:价差+分红(分红成分进盯市列)' + ELSE '' END AS 事件诊断 +FROM swap_flow_event sfe +WHERE sfe.SwapTradeId = @TargetTradeId + AND sfe.DataState = 100 + AND sfe.EventType IN (2,3,4) +ORDER BY sfe.PositionId, sfe.EventDate, sfe.EventType; + +-- 段2 EOD逐日:盯市列 vs 分红列(同日同腿,分红同时出现在两列) +SELECT esp.ValueDate, + esp.PositionId, + esp.TdCloseQty, + esp.UnderlyingPrice AS 当日盯市价, + esp.PosiGrossPrice AS 期初成本价, + esp.TdCloseMtmPnl AS 当日盯市列, + esp.RealizedMtmPnL AS 累计盯市列, + esp.TdCloseDividend AS 当日分红列, + esp.RealizedDividend AS 累计分红列, + esp.TdCloseFee AS 当日费用列, + esp.TdCloseInterest AS 当日利息列, + esp.RealizedPnl AS 持仓层累计已实现, + CASE WHEN esp.TdCloseMtmPnl <> 0 AND esp.TdCloseDividend <> 0 + THEN CONCAT('分红', esp.TdCloseDividend, '同时进盯市列和分红列') + ELSE '' END AS 当日诊断 +FROM eod_swap_position esp +WHERE esp.SwapTradeId = @TargetTradeId + AND (esp.TdCloseMtmPnl <> 0 OR esp.TdCloseDividend <> 0) +ORDER BY esp.PositionId, esp.ValueDate; + +-- 段3 累计对照:按 PositionId 取最终累计,算出盯市列里的分红成分 +-- 盯市列里的分红成分 = 该腿所有平仓/互换事件的 DividendIn 之和 +SELECT fin.PositionId, + fin.RealizedMtmPnL AS 最终累计盯市列, + fin.RealizedDividend AS 最终累计分红列, + fin.RealizedFee AS 最终累计费用列, + fin.RealizedInterest AS 最终累计利息列, + fin.RealizedPnl AS 最终持仓层已实现, + dv.盯市列分红成分, + (fin.RealizedMtmPnL - dv.盯市列分红成分 - fin.RealizedFee) AS 盯市列纯价差成分 +FROM (SELECT PositionId, RealizedMtmPnL, RealizedDividend, RealizedFee, RealizedInterest, RealizedPnl + FROM eod_swap_position esp + WHERE esp.SwapTradeId = @TargetTradeId + AND esp.id IN (SELECT MAX(id) FROM eod_swap_position + WHERE SwapTradeId = @TargetTradeId GROUP BY PositionId) + ) fin +LEFT JOIN (SELECT PositionId, SUM(DividendIn) AS 盯市列分红成分 + FROM swap_flow_event + WHERE SwapTradeId = @TargetTradeId AND DataState = 100 AND EventType IN (2,3,4) + GROUP BY PositionId) dv ON dv.PositionId = fin.PositionId +ORDER BY fin.PositionId; + +-- 段4 一句话结论:重复金额合计 = 盯市列里的分红成分之和 +SELECT @TargetTradeId AS SwapTradeId, + SUM(盯市列分红成分) AS 重复计入分红金额, + (SELECT SUM(RealizedPnl) FROM eod_swap_position + WHERE SwapTradeId = @TargetTradeId + AND id IN (SELECT MAX(id) FROM eod_swap_position + WHERE SwapTradeId = @TargetTradeId GROUP BY PositionId)) AS 当前RealizedPnl合计, + CASE WHEN ABS(SUM(盯市列分红成分)) > 0.01 + THEN CONCAT('坐实重复计算: 分红 ', SUM(盯市列分红成分), + ' 既在 RealizedMtmPnL(盯市列) 又在 RealizedDividend(分红列)', + ', 修复后 RealizedPnl 应减少 ', SUM(盯市列分红成分)) + ELSE '未检测到重复(可能已修复或无分红平仓/互换事件)' END AS 结论 +FROM (SELECT PositionId, SUM(DividendIn) AS 盯市列分红成分 + FROM swap_flow_event + WHERE SwapTradeId = @TargetTradeId AND DataState = 100 AND EventType IN (2,3,4) + GROUP BY PositionId) t; +-- 预期结果: +-- 1875(纯分红型) -> 重复计入 302400.00(MarkClosePnl 全是分红,价差=0) +-- 1891(混合型) -> 重复计入 -18.66 (MarkClosePnl 含价差395604 + 分红-18.66) + + -- ============================================================================ -- 第 3 步:生命周期守恒校验(累计已实现分红 vs 理论应付分红) -- ============================================================================