From b879481d71ba83ab9708b103123770c5dda8b810 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Mon, 18 May 2026 18:43:46 +0000 Subject: [PATCH] monitoring(wealth): per-vest realized PNL via FIFO sell-match New table panel below the per-sell breakdown. For each vest, FIFO-match its shares against the subsequent sells (shares from earlier vests get sold first), and aggregate the matched portions: realized_pnl = SUM(matched_qty * (sell_price - vest_price)) pnl_pct = realized_pnl / SUM(matched_qty * vest_price) * 100 days_held = AVG(sell_date - vest_date) per matched portion Footer reducer sums shares, vest value, sell value, and realized PNL so the bottom row is the full-portfolio realized take. --- .../modules/monitoring/dashboards/wealth.json | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/stacks/monitoring/modules/monitoring/dashboards/wealth.json b/stacks/monitoring/modules/monitoring/dashboards/wealth.json index 9200e038..fad5666d 100644 --- a/stacks/monitoring/modules/monitoring/dashboards/wealth.json +++ b/stacks/monitoring/modules/monitoring/dashboards/wealth.json @@ -2764,6 +2764,229 @@ "rawSql": "SELECT activity_date::date::timestamp AS \"time\", SUM(quantity*unit_price) AS \"vest value\", SUM(quantity) AS \"shares\" FROM activities WHERE asset_id='4f60833d-0bfb-484f-8ee6-f129af72e137' AND activity_type='BUY' GROUP BY activity_date::date ORDER BY activity_date::date" } ] + }, + { + "id": 31, + "title": "META vests — realized PNL (FIFO-matched against sells)", + "description": "One row per vest with realized P&L computed by FIFO-matching that vest's shares against subsequent sells. Each vest's shares may be spread across multiple sells; the matched sell-price column is the weighted average. 'Avg days held' is the average gap between this vest's date and the sell dates that consumed its shares. Compare against panel 28 to see realized vs hypo-if-held.", + "type": "table", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "wealth-pg" + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 162 + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "decimals": 2 + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "shares sold" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "vest price" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "unit", + "value": "currencyUSD" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "vest value" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "unit", + "value": "currencyUSD" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "avg sell price" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "unit", + "value": "currencyUSD" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "sell value" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "unit", + "value": "currencyUSD" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "realized PNL" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "unit", + "value": "currencyUSD" + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 0 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PNL %" + }, + "properties": [ + { + "id": "decimals", + "value": 1 + }, + { + "id": "unit", + "value": "percent" + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 0 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "days held (avg)" + }, + "properties": [ + { + "id": "decimals", + "value": 0 + }, + { + "id": "unit", + "value": "d" + } + ] + } + ] + }, + "options": { + "cellHeight": "sm", + "footer": { + "show": true, + "reducer": [ + "sum" + ], + "fields": [ + "shares sold", + "vest value", + "sell value", + "realized PNL" + ] + } + }, + "targets": [ + { + "refId": "A", + "datasource": { + "type": "grafana-postgresql-datasource", + "uid": "wealth-pg" + }, + "rawQuery": true, + "editorMode": "code", + "format": "table", + "rawSql": "WITH lots AS (SELECT id, activity_date::date AS vest_date, quantity, unit_price AS vest_price, SUM(quantity) OVER (ORDER BY activity_date, id) AS lot_end, SUM(quantity) OVER (ORDER BY activity_date, id) - quantity AS lot_start FROM activities WHERE asset_id='4f60833d-0bfb-484f-8ee6-f129af72e137' AND activity_type='BUY'), sells AS (SELECT activity_date::date AS sell_date, quantity AS sell_qty, unit_price AS sell_price, SUM(quantity) OVER (ORDER BY activity_date, id) AS sell_end, SUM(quantity) OVER (ORDER BY activity_date, id) - quantity AS sell_start FROM activities WHERE asset_id='4f60833d-0bfb-484f-8ee6-f129af72e137' AND activity_type='SELL'), matched AS (SELECT l.vest_date, l.vest_price, s.sell_date, s.sell_price, GREATEST(LEAST(l.lot_end, s.sell_end) - GREATEST(l.lot_start, s.sell_start), 0::numeric) AS qty FROM lots l CROSS JOIN sells s WHERE LEAST(l.lot_end, s.sell_end) > GREATEST(l.lot_start, s.sell_start)) SELECT vest_date, SUM(qty) AS \"shares sold\", (SUM(qty*vest_price)/NULLIF(SUM(qty),0)) AS \"vest price\", SUM(qty*vest_price) AS \"vest value\", (SUM(qty*sell_price)/NULLIF(SUM(qty),0)) AS \"avg sell price\", SUM(qty*sell_price) AS \"sell value\", SUM(qty*(sell_price-vest_price)) AS \"realized PNL\", (SUM(qty*(sell_price-vest_price))/NULLIF(SUM(qty*vest_price),0)*100) AS \"PNL %\", AVG((sell_date-vest_date)) AS \"days held (avg)\" FROM matched GROUP BY vest_date ORDER BY vest_date" + } + ] } ], "refresh": "5m",