Search code examples
sql-servert-sqlgroup-bytimestampfinance

Group OHLC-Stockmarket Data into multiple timeframes with T-SQL


I'm using SQL Server 2008 R2 and need to create new tables grouped in Time intervals.

The data is data from a stock market index. I have the data in 1 minute intervals, now i need them in 5,10,15,30,45,60...minute intervals. My primary key is the time stamp.

My question is: how to query the 1 minute data table to return data that is grouped by a specific time interval for example 5 minute intervals.

The query must return the Highest, Lowest, Last and First values in that particular group and most importantly also the last entry of the time-stamp in the group.

I'm very new to the SQL language and have tried numerous code found on the net, but i cant get to exactly return the desired results.

Data:

TimeStamp          | Open | High | Low | Close
2012-02-17 15:15:0 | 102  | 110  |100  |105
2012-02-17 15:16:0 |106   |112   |105  |107
2012-02-17 15:17:0 | 106  |110   |98   |105
2012-02-17 15:18:0 |105   |109   |104  |106
2012-02-17 15:19:0 |107   |112   |107  |112
2012-02-17 15:20:0 |115   |125   |115  |124

Desired Query Result (5 minutes):

Timestamp       |Open|High|Low|Close
2012-02-15:19:0 |102 |125 |98 |124
2012-02-15:24:0 |115.|....|...|...
2012-02-15:29:0 |....|....|...|...

Solution

  • When you convert a datetime to a float, you get a number of days. If you multiply that by 24 * 12, you get a number of 5 minute intervals. So if you group on:

    cast(cast(timestamp as float) * 24 * 12 as int)
    

    you can do aggregates per five minutes:

    select  min(timestamp)
    ,       max(high) as Highest
    ,       min(low) as Lowest
    from    @t
    group by
            cast(cast(timestamp as float) * 24 * 12 as int)
    

    Finding the first and the last row is tricky in SQL Server. Here's one way using row_number:

    select  min(timestamp)
    ,       max(high) as Highest
    ,       min(low) as Lowest
    ,       min(case when rn_asc = 1 then [open] end) as first
    ,       min(case when rn_desc = 1 then [close] end) as Last
    from    (
            select  row_number() over (
                        partition by cast(cast(timestamp as float) * 24 * 12 as int)
                        order by timestamp) as rn_asc
            ,       row_number() over (
                        partition by cast(cast(timestamp as float) * 24 * 12 as int)
                        order by timestamp desc) as rn_desc
            ,       *
            from    @t
            ) as SubQueryAlias
    group by
            cast(cast(timestamp as float) * 24 * 12 as int)
    

    Here's a working example at SE Data.