Create candlestick charts with native PostgreSQL first-last-aggregate
When you want to create Candlestick charts you need to group time series into time-frames like: Give me the highest, lowest and average value for each 1 hour of a day. To do so, you can use this native PostgreSQL query:
select
min(cp.created) as created_min,
max(cp.created) as created_max,
cp.symbol_id,
avg(cp.price) price_avg,
max(cp.price) price_max,
min(cp.price) price_min
from
generate_series(current_timestamp::timestamp-interval '7' day, current_timestamp::timestamp, interval '1' hour) as d(dt)
join prices cp on (cp.created >= d.dt and cp.created < d.dt + interval '1' hour)
where cp.symbol_id = 'LHA.DE'
group by d.dt, cp.symbol_id
order by d.dt;
You will get a result like
2024-09-16 09:00:00.000000 +00:00,2024-09-16 09:25:00.000000 +00:00,LHA.DE,5.8473333517710367,5.8520002365112305,5.8420000076293945
2024-09-16 09:30:00.000000 +00:00,2024-09-16 10:25:00.000000 +00:00,LHA.DE,5.8581666946411132,5.872000217437744,5.840000152587891
2024-09-16 10:30:00.000000 +00:00,2024-09-16 11:25:00.000000 +00:00,LHA.DE,5.8568333784739175,5.872000217437744,5.8480000495910645
2024-09-16 11:30:00.000000 +00:00,2024-09-16 12:25:00.000000 +00:00,LHA.DE,5.8531666994094847,5.868000030517578,5.843999862670898
2024-09-16 12:30:00.000000 +00:00,2024-09-16 13:25:00.000000 +00:00,LHA.DE,5.8460001078518953,5.8520002365112305,5.840000152587891
2024-09-16 13:30:00.000000 +00:00,2024-09-16 14:25:00.000000 +00:00,LHA.DE,5.8504999876022337,5.869999885559082,5.843999862670898
2024-09-16 14:30:00.000000 +00:00,2024-09-16 15:25:00.000000 +00:00,LHA.DE,5.8638333479563393,5.868000030517578,5.855999946594238
2024-09-16 15:30:00.000000 +00:00,2024-09-16 16:25:00.000000 +00:00,LHA.DE,5.8645000060399373,5.875999927520752,5.8480000495910645
2024-09-16 16:30:00.000000 +00:00,2024-09-16 17:25:00.000000 +00:00,LHA.DE,5.8793332974116008,5.888000011444092,5.861999988555908
2024-09-16 17:35:00.000000 +00:00,2024-09-16 17:35:00.000000 +00:00,LHA.DE,5.886,5.886,5.886
...
But for typical candlesticks, you need to know the first and the last value of each group as well. This feature is available in extensions like TimescaleDB, or you take the native plugin extension postgresql-first-last-aggregate on GitHub, to achieve this with vanilla PostgreSQL without downsides in performance.
Just load the first_last_aggregate.sql
into your scheme and extend the query above by the two lines:
first(cp.price) price_open,
last(cp.price) price_close,