Je hebt de jouwe tot op de minuut gegroepeerd. Waarvan ik ga aannemen dat het verkeerd is, omdat deze meestal overdag worden gedaan. Als ik het mis heb, moet je het terug veranderen.
SELECT DISTINCT contract_id, ts::date,
min(price) OVER w,
max(price) OVER w,
first_value(price) OVER w,
last_value(price) OVER w
FROM fill
WINDOW w AS (PARTITION BY contract_id, ts::date ORDER BY ts)
ORDER BY 1,2