I have minute to minute financial records stored in similar format in my table,
dt | open | high | low | close | vol
---------------------+----------+----------+----------+----------+-------
2018-05-04 15:30:00 | 171.0000 | 171.3000 | 170.9000 | 171.0000 | 42817
2018-05-04 15:29:00 | 170.8000 | 171.0000 | 170.8000 | 170.9500 | 32801
2018-05-04 15:28:00 | 170.8500 | 171.0000 | 170.8000 | 170.8000 | 22991
2018-05-04 15:27:00 | 170.8500 | 170.8500 | 170.7500 | 170.8000 | 40283
2018-05-04 15:26:00 | 170.9500 | 171.0000 | 170.8000 | 170.8500 | 46636
and so on.
I want to group them into blocks of 5 minutes, 10 minutes, 60 minutes just like candlesticks. Using date_trunc('hour', dt)
is not possible as I want to group them as block of last 60 minutes, last 15 minutes etc.
I am using PostgreSQL.
You should use a GROUP BY
with :
floor(extract('epoch' from dt) / 300)
to have your data grouped in 5 minutes intervals. 300 is the number of seconds in 5 minutes. Thus if you want 10 minutes, you'd divide by 600. If you want 1 hour, by 3600.
If you want your interval to begin at 00 05 10, use floor()
. If you want them to finish at 00, 05, 10, use ceil()
In the SELECT
clause, you should re-transform the Unix epoch used in the GROUP BY
into a timestamp using
to_timestamp(floor((extract('epoch' from dt) / 300)) * 300) as ts
Its not clear if you want all the "block" results in the same query, I assumed yes if you want a candlestick graph. I have also logically deduced the right aggregate function (MIN, MAX, AVG, SUM) for each column, following their names . You might have to adapt this.
Here we go :
SELECT '5 minutes' as block,
to_timestamp(floor((extract('epoch' from dt) / 300)) * 300) as ts,
round(AVG(open),4) as avg_open,
round(MAX(high),4) as max_high,
round(MIN(low),4) as min_low,
round(AVG(close),4) as avg_close,
SUM(vol) as sum_vol
FROM mytable
GROUP BY floor(extract('epoch' from dt) / 300)
UNION ALL
SELECT '10 minutes' as block,
to_timestamp(floor((extract('epoch' from dt) / 600)) * 600) as ts,
round(AVG(open),4) as avg_open,
round(MAX(high),4) as max_high,
round(MIN(low),4) as min_low,
round(AVG(close),4) as avg_close,
SUM(vol) as sum_vol
FROM mytable
GROUP BY floor(extract('epoch' from dt) / 600)
UNION ALL
SELECT '1 hour' as block,
to_timestamp(floor((extract('epoch' from dt) / 3600)) * 3600) as ts,
round(AVG(open),4) as avg_open,
round(MAX(high),4) as max_high,
round(MIN(low),4) as min_low,
round(AVG(close),4) as avg_close,
SUM(vol) as sum_vol
FROM mytable
GROUP BY floor(extract('epoch' from dt) / 3600)
Results:
block ts avg_open max_high min_low avg_close sum_vol
5 minutes 04.05.2018 17:30:00 171 171,3 170,9 171 42817
5 minutes 04.05.2018 17:25:00 170,8625 171 170,75 170,85 142711
10 minutes 04.05.2018 17:20:00 170,8625 171 170,75 170,85 142711
10 minutes 04.05.2018 17:30:00 171 171,3 170,9 171 42817
1 hour 04.05.2018 17:00:00 170,89 171,3 170,75 170,88 185528
Test it on REXTESTER
You can use generate_series()
to create any range you want
SELECT dd as start_range, dd + '30 min'::interval as end_range
FROM generate_series
( '2018-05-05'::timestamp
, '2018-05-06'::timestamp
, '30 min'::interval) dd
;
Then check if your record fall on that range.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.