I am trying to query a table in PostgreSQL 8.4.2 server for to get open-high-low-close data. The table and my first query are below.
Question: Is there a way to get the same results without using subqueries as in the example query below? Perhaps using FIRST_VALUE() or LAST_VALUE() window methods?
-- FIRST ATTEMPT AT OHLC
SELECT
contract_id
, TO_CHAR(ts, 'YYMMDDHH24MI')
, (SELECT price FROM fill minF WHERE minF.fill_id = MIN(f.fill_id)) AS open
, MAX(f.price) AS high
, MIN(f.price) AS low
, (SELECT price FROM fill maxF WHERE maxF.fill_id = MAX(f.fill_id)) AS close
FROM fill f
GROUP BY 1,2
ORDER BY 1,2;
-- SIMPLIFIED DDL
CREATE TABLE fill
(
contract_id SEQUENCE PRIMARY KEY
, ts TIMESTAMP
, price NUMERIC(10,4)
);
You have yours grouped down to the minute. Which I'm going to assume is wrong because these are typically done by day. If I'm wrong, you'll have to change it back.
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
I would like to get sub-day resolution. This appears to work well.
SELECT
contract_id
, the_minute
, open
, high
, low
, close
FROM
(
SELECT
contract_id
, TO_CHAR(ts, 'YYMMDDHH24MI') AS the_minute
, MIN(price) OVER w AS low
, MAX(price) OVER w AS high
, LAST_VALUE(price) OVER w AS open -- Note the window is in reverse (first value comes last)
, FIRST_VALUE(price) OVER w AS close -- Note the window is in reverse (last value comes first)
, RANK() OVER w AS the_rank
FROM fill
WINDOW w AS (PARTITION BY contract_id, TO_CHAR(ts, 'YYMMDDHH24MI') ORDER BY fill_id DESC)
) AS inr
WHERE the_rank = 1
ORDER BY 1, 2;
Thank you, Scott. You answer helped me get to the following solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With