从交易清单中确定谨慎期间的价格

时间:2018-02-18 09:47:29

标签: sql sql-server

我从商品交易所获得了一份谨慎的历史交易清单,其中包括日期时间和价值。

tradeTime                  |  price
-----------------------------------
2014-06-11T00:21:12+02:00  |  647.24
2014-06-11T00:23:12+02:00  |  700.18
2014-06-11T00:28:12+02:00  |  750.23
2014-06-11T00:40:00+02:00  |  767.81
2014-06-11T00:51:12+02:00  |  711.46

现在我希望能够每小时创建一个价格清单。因此,三种逻辑可能性是:

  1. 那个时期有1笔交易 - 很棒,这就是价格(开盘和收盘)
  2. 有多笔交易 - 第一笔是开盘价,最后一笔是收盘价
  3. 没有交易 - 开放和开放收盘价应该是该期间之前的最新交易。
  4. 因此,使用上面的示例,查看10分钟的增量,输出应该类似于:

    period         |  open    | close
    --------------------------------
    00:20 -> 00:30 |  648.24  | 750.23
    00:30 -> 00:40 |  750.23  | 767.81
    00:40 -> 00:50 |  767.81  | 711.46
    

    -

    SELECT * FROM sales BETWEEN From_date AND To_date
    

    可能有MIN()MAX()日期来选择价格?

    我不确定这一切是如何结合在一起的

4 个答案:

答案 0 :(得分:1)

尝试此查询:

WITH qq AS (
  SELECT cast('2014-06-11T00:00:00' as datetime) as startTime,
         dateadd( minute, 10, cast('2014-06-11T00:00:00' as datetime)) as endTime
  UNION ALL
  SELECT endTime, dateadd( minute, 10, endTime )
  FROM qq
  WHERE endTime < cast('2014-06-12T00:00:00' as datetime) 
)
SELECT startTime, endTime,
       coalesce( opening, opening1 ) as opening,
       coalesce( closing, opening, opening1 ) as closing
FROM (
   SELECT qq.startTime, qq.endTime,
       (SELECT TOP 1 price FROM table1 t1 
        WHERE t1.tradeTime >= qq.startTime AND t1.tradeTime < qq.endTime
        ORDER BY t1.tradeTime ) As opening,
       (SELECT TOP 1 price FROM table1 t1 
        WHERE t1.tradeTime >= qq.startTime AND t1.tradeTime < qq.endTime
        ORDER BY t1.tradeTime DESC ) As closing,
       (SELECT TOP 1 price FROM table1 t1 
        WHERE t1.tradeTime < qq.startTime
        ORDER BY t1.tradeTime DESC ) as opening1
   FROM qq
) x
option (maxrecursion 0)

演示:http://sqlfiddle.com/#!18/b9363/6

|            startTime |              endTime | opening | closing |
|----------------------|----------------------|---------|---------|
| 2014-06-11T00:00:00Z | 2014-06-11T00:10:00Z |  (null) |  (null) |
| 2014-06-11T00:10:00Z | 2014-06-11T00:20:00Z |  (null) |  (null) |
| 2014-06-11T00:20:00Z | 2014-06-11T00:30:00Z |  647.24 |  750.23 |
| 2014-06-11T00:30:00Z | 2014-06-11T00:40:00Z |  750.23 |  750.23 |
| 2014-06-11T00:40:00Z | 2014-06-11T00:50:00Z |  767.81 |  767.81 |
| 2014-06-11T00:50:00Z | 2014-06-11T01:00:00Z |  711.46 |  711.46 |
| 2014-06-11T01:00:00Z | 2014-06-11T01:10:00Z |  711.46 |  711.46 |
| 2014-06-11T01:10:00Z | 2014-06-11T01:20:00Z |  711.46 |  711.46 |
| 2014-06-11T01:20:00Z | 2014-06-11T01:30:00Z |  711.46 |  711.46 |
| 2014-06-11T01:30:00Z | 2014-06-11T01:40:00Z |  711.46 |  711.46 |
| 2014-06-11T01:40:00Z | 2014-06-11T01:50:00Z |  711.46 |  711.46 |
| 2014-06-11T01:50:00Z | 2014-06-11T02:00:00Z |  711.46 |  711.46 |
...
...
...

答案 1 :(得分:0)

您需要从小时列表开始。因为您可能没有交易,所以您需要生成此交易。假设你只需要几个小时 - 比如一天中的所有小时 - 一个递归的CTE就足够了:

with hours as (
      select cast('2014-06-11' as datetime) as yyyymmddhh
      union all
      select dateadd(hour, 1, yyyymmddhh)
      from hours
      where dateadd(hour, 1, yyyymmddhh) < '2014-06-12'
     )

然后,您可以使用apply

执行您想要的操作
with hours as (
      select cast('2014-06-11' as datetime) as yyyymmddhh
      union all
      select dateadd(hour, 1, yyyymmddhh)
      from cte
      where dateadd(hour, 1, yyyymmddhh) < '2014-06-12'
     )
select h.*, opening.price, closing.price
from hours h outer apply
     (select top 1 t.*
      from t
      where tradetime < dateadd(hour, 1, yyyymmddhh)
      order by (case when cast(tradetime as date) = cast(yyyymmddhh as date) and
                          datepart(hour, tradetime) = datepart(hour, yyyymddhh)
                     then 1
                     else 0
                end),
               (case when cast(tradetime as date) = cast(yyyymmddhh as date) and
                          datepart(hour, tradetime) = datepart(hour, yyyymddhh)
                     then tradetime
                end) asc,
               tradetime desc
    ) opening outer apply
    (select top 1 t.*
      from t
      where tradetime < dateadd(hour, 1, yyyymmddhh)
      order by (case when cast(tradetime as date) = cast(yyyymmddhh as date) and
                          datepart(hour, tradetime) = datepart(hour, yyyymddhh)
                     then 1
                     else 0
                end),
               tradetime desc
    ) closing;

答案 2 :(得分:0)

下午好,

我不确定我的解决方案是否真的对您有所帮助,因为我不能检查代码是否有效或者为什么没有,我会尝试这些行:

SELECT prices FROM trades WHERE(SELECT MIN(DATEPART(MINUTE, trades.dates)), 
MAX(DATEPART(MINUTE, trades.dates)) WHERE(SELECT DISTINCT DATEPART(HOUR, 
trades.dates));

这个想法是在每个不同的小时内查询分钟的最小值和最大值,然后查询分钟1和分钟60的相关价格,以便获得开盘价和收盘价。

我希望这有助于您继续解决问题,或者至少为您提供可能的解决方案。

祝福,

M.S。

答案 3 :(得分:0)

以下查询应该给你一个开始。

 SELECT DISTINCT Disp,
       (
        CASE WHEN [Open] IS NOT NULL THEN [Open]
        ELSE (SELECT TOP 1 PRICE FROM @Table 
            WHERE Datepart(MINUTE, TradeTime) / 10 < O.Diff )
        END
       ) AS [Open]
       ,(
        CASE WHEN O.[Open] IS NOT NULL THEN [Open]
        ELSE (SELECT TOP 1 PRICE FROM @Table 
            WHERE Datepart(MINUTE, TradeTime) / 10 < O.Diff )
        END
       ) AS [Close]

       FROM
       (
        SELECT  
        D.Disp
       ,D.Diff
       ,FIRST_VALUE(Price) OVER (PARTITION BY GRP  
                           ORDER BY TradeTime ASC) AS [Open]
       ,FIRST_VALUE(Price) OVER (PARTITION BY GRP 
                           ORDER BY TradeTime DESC)  AS [Close],
        TradeTime
   FROM (VALUES (0,'00:01->00:10'),
                (1,'00:10->00:20'), 
                (2,'00:20->00:30'), 
                (3,'00:30->00:40'), 
                (4,'00:40->00:50'), 
                (5,'00:50->00:59') 
                ) D(Diff,Disp) 
        LEFT JOIN (SELECT Datepart(MINUTE, TradeTime) / 10 AS GRP, 
                         TradeTime, 
                         Price 
                  FROM   @Table 
                  GROUP  BY Datepart(MINUTE, TradeTime) / 10, 
                            TradeTime, 
                            Price) T 
                  ON T.GRP = D.Diff 
              ) O

完成示例:

DECLARE @Table TABLE(TradeTime DATETIME, Price DECIMAL(15,2))
INSERT INTO @Table
  SELECT * FROM
  (VALUES 
  (CAST('2018-02-18 13:04:46.920' AS DATETIME)  ,  647.24)
 ,(CAST('2018-02-18 13:05:46.920' AS DATETIME) ,  700.18)
 ,(CAST('2018-02-18 13:15:46.920' AS DATETIME)  ,  750.23)
 ,(CAST('2018-02-18 13:24:46.920' AS DATETIME) ,  767.81)
 ,(CAST('2018-02-18 14:26:46.920' AS DATETIME)  ,  711.46)


   ) TAB(TradeTime, Price)



      SELECT DISTINCT Disp,
       (
        CASE WHEN [Open] IS NOT NULL THEN [Open]
        ELSE (SELECT TOP 1 PRICE FROM @Table 
            WHERE Datepart(MINUTE, TradeTime) / 10 < O.Diff )
        END
       ) AS [Open]
       ,(
        CASE WHEN O.[Open] IS NOT NULL THEN [Open]
        ELSE (SELECT TOP 1 PRICE FROM @Table 
            WHERE Datepart(MINUTE, TradeTime) / 10 < O.Diff )
        END
       ) AS [Close]

       FROM
       (
        SELECT  
        D.Disp
       ,D.Diff
       ,FIRST_VALUE(Price) OVER (PARTITION BY GRP  
                           ORDER BY TradeTime ASC) AS [Open]
       ,FIRST_VALUE(Price) OVER (PARTITION BY GRP 
                           ORDER BY TradeTime DESC)  AS [Close],
        TradeTime
   FROM (VALUES (0,'00:00->00:10'),
                (1,'00:10->00:20'), 
                (2,'00:20->00:30'), 
                (3,'00:30->00:40'), 
                (4,'00:40->00:50'), 
                (5,'00:50->00:59') 
                ) D(Diff,Disp) 
        LEFT JOIN (SELECT Datepart(MINUTE, TradeTime) / 10 AS GRP, 
                         TradeTime, 
                         Price 
                  FROM   @Table 
                  GROUP  BY Datepart(MINUTE, TradeTime) / 10, 
                            TradeTime, 
                            Price) T 
                  ON T.GRP = D.Diff 
              ) O

示例输出

Disp            Open        Close
--------------------------------------
00:00->00:10    647.24      647.24
00:10->00:20    750.23      750.23
00:20->00:30    767.81      767.81
00:30->00:40    647.24      47.24
00:40->00:50    647.24      647.24
00:50->00:59    647.24      647.24