Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 35 additions & 32 deletions api/v1_users_balance_history.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,44 +96,47 @@ func (app *ApiServer) v1UsersBalanceHistory(c *fiber.Ctx) error {
return err
}

// Build SQL query with granularity parameter.
// First sum balance_usd across mints at each hourly snapshot to get the
// total portfolio value per hour. For 'daily', pick the latest hour within
// each day (end-of-day balance) — do NOT sum balances across hours, since
// each hour is a point-in-time snapshot, not an additive quantity.
// total portfolio value per hour.
sql := `
WITH hourly_totals AS (
SELECT
timestamp,
SUM(balance_usd) AS balance_usd
FROM user_balance_history
WHERE user_id = @user_id
AND timestamp >= @start_time
AND timestamp <= @end_time
GROUP BY timestamp
),
bucketed AS (
SELECT
CASE
WHEN @granularity::text = 'daily' THEN date_trunc('day', timestamp)
ELSE timestamp
END AS bucket_timestamp,
timestamp AS source_timestamp,
SELECT
timestamp,
SUM(balance_usd) AS balance_usd
FROM user_balance_history
WHERE user_id = @user_id
AND timestamp >= @start_time
AND timestamp <= @end_time
GROUP BY timestamp
ORDER BY timestamp ASC
`

if params.Granularity == GranularityDaily {
// For daily, pick the latest hour within each day (end-of-day balance).
// Do not sum balances across hours, since each hour is a point-in-time
// snapshot, not an additive quantity.
sql = `
WITH hourly_totals AS (
SELECT
timestamp,
SUM(balance_usd) AS balance_usd
FROM user_balance_history
WHERE user_id = @user_id
AND timestamp >= @start_time
AND timestamp <= @end_time
GROUP BY timestamp
)
SELECT DISTINCT ON (date_trunc('day', timestamp))
date_trunc('day', timestamp) AS timestamp,
balance_usd
FROM hourly_totals
)
SELECT DISTINCT ON (bucket_timestamp)
bucket_timestamp AS timestamp,
balance_usd
FROM bucketed
ORDER BY bucket_timestamp ASC, source_timestamp DESC
`
ORDER BY date_trunc('day', hourly_totals.timestamp) ASC, hourly_totals.timestamp DESC
`
}

rows, err := app.pool.Query(c.Context(), sql, pgx.NamedArgs{
"user_id": userId,
"start_time": startTime,
"end_time": endTime,
"granularity": string(params.Granularity),
"user_id": userId,
"start_time": startTime,
"end_time": endTime,
})
if err != nil {
return err
Expand Down
Loading