Search code examples
sqlpostgresqlfinance

Querying PostgreSQL for Open-High-Low-Close (OHLC) report


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)
);

Solution

  • 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.