【问题标题】:How to query Open-high-low-close (OHLC) data from SQL Server如何从 SQL Server 查询 Open-high-low-close (OHLC) 数据
【发布时间】:2010-12-02 06:56:31
【问题描述】:

我正在尝试直接从数据库中检索高低收盘 (OHLC) 图表的数据,这是您看到的股票图表。这是可能的,如果,如何?

我有一张这样的表(简化版):

日期 |价格 |价格类型

每天都会创建一个记录,我将每月/每年报告一次,而不是每天报告股票。

我想查询如下内容:

SELECT PriceType, MAX(Price) as High, MIN(Price) as Low, [Price of the first item of the month] as Open, [Price of last item of the month] as Close GROUP BY PriceType, Year(Date),月(日)

要访问 SQL Server,我使用 LLBLGen,因此基于该技术的 anwser 会很棒,通用 SQL Server 也可以!

是 SQL 2005,但 2008 也是一个选项。

谢谢。

【问题讨论】:

  • 回复了你对我的回答的评论

标签: sql-server group-by finance stocks


【解决方案1】:

这是我写的一个小查询,似乎一次可以很好地工作一段时间。您需要做的就是评论选择的 DATEPARTS 以获得您正在寻找的时间跨度。或者,您可以针对不同的时间跨度制作多个视图。基础数据表也使用 Bid Ask 报价类型数据。如果您使用的是中间价或最后价,则可以从选择中删除 case 语句。

Select 
tmp.num,
rf.CurveName, 
rf.Period as Period,
CASE WHEN (tmp2.Bid is null or tmp2.Ask is null) then isnull(tmp2.Bid,0)+isnull(tmp2.Ask,0) else (tmp2.Bid+tmp2.Ask)/2 end as [Open],
tmp.Hi,
tmp.Lo,
CASE WHEN (rf.Bid is null or Rf.Ask is null) then isnull(rf.Bid,0)+isnull(rf.Ask,0) else (rf.Bid+rf.Ask)/2 end as [Close],
tmp.OpenDate,
tmp.CloseDate,
tmp.yr,
tmp.mth,
tmp.wk,
tmp.dy,
tmp.hr
from BidAsk rf inner join 
(SELECT count(CurveName)as num,CurveName,
Period,
max(CASE WHEN (Bid is null or Ask is null) then isnull(Bid,0)+isnull(Ask,0) else (Bid+Ask)/2 end) as Hi,
min(CASE WHEN (Bid is null or Ask is null) then isnull(Bid,0)+isnull(Ask,0) else (Bid+Ask)/2 end) as Lo, 
max(CurveDateTime) as CloseDate, min(CurveDateTime) as OpenDate,
    DATEPART(year, CurveDateTime) As yr,  
    DATEPART(month, CurveDateTime) As mth,  
    DATEPART(week, CurveDateTime) As wk,  
    DATEPART(Day, CurveDateTime) as dy,
    DATEPART(Hour, CurveDateTime) as hr  
    --DATEPART(minute, CurveDateTime) as mnt 
FROM  
    BidAsk 
GROUP BY  
CurveName,Period,
    DATEPART(year, CurveDateTime),  
    DATEPART(month, CurveDateTime),  
    DATEPART(week, CurveDateTime),
    DATEPART(Day, CurveDateTime) ,
    DATEPART(Hour, CurveDateTime)
    --DATEPART(minute, CurveDateTime) 
) tmp on 
tmp.CurveName=rf.CurveName and 
tmp.CloseDate=rf.CurveDateTime and 
tmp.Period=rf.Period

inner join BidAsk tmp2 on 
tmp2.CurveName=rf.CurveName and 
tmp2.CurveDateTime=tmp.Opendate and 
tmp2.Period=rf.Period

ORDER BY  
CurveName,Period,tmp.yr,tmp.mth
    --DATEPART(year, CurveDateTime), 
    --DATEPART(month, CurveDateTime)  
    --DATEPART(day, CurveDateTime),  
    --DATEPART(Hour, CurveDateTime), 
    --DATEPART(minute, CurveDateTime) ) 

【讨论】:

    【解决方案2】:

    这似乎有效。很可能有一种不那么冗长的方法。

    --create test data
    CREATE TABLE #t
    (priceDate DATETIME
    ,price MONEY
    ,priceType CHAR(1)
    )
    
    INSERT #t
          SELECT '20090101',100,'A'
    UNION SELECT '20090102',500,'A'
    UNION SELECT '20090103',20 ,'A'
    UNION SELECT '20090104',25 ,'A'
    UNION SELECT '20090105',28 ,'A'
    UNION SELECT '20090131',150,'A'
    
    
    UNION SELECT '20090201',501,'A'
    UNION SELECT '20090203',21 ,'A'
    UNION SELECT '20090204',26 ,'A'
    UNION SELECT '20090205',29 ,'A'
    UNION SELECT '20090228',151,'A'
    
    
    UNION SELECT '20090101',100,'B'
    UNION SELECT '20090102',500,'B'
    UNION SELECT '20090103',20 ,'B'
    UNION SELECT '20090104',25 ,'B'
    UNION SELECT '20090105',28 ,'B'
    UNION SELECT '20090131',150,'B'
    
    
    UNION SELECT '20090201',501,'B'
    UNION SELECT '20090203',21 ,'B'
    UNION SELECT '20090204',26 ,'B'
    UNION SELECT '20090205',29 ,'B'
    UNION SELECT '20090228',151,'B'
    
    --query
    ;WITH rangeCTE
    AS
    (
            SELECT  MIN(priceDate) minDate
                    ,MAX(priceDate) maxDate
            FROM #t
    )
    ,datelistCTE
    AS
    (
            SELECT CAST(CONVERT(CHAR(6),minDate,112) + '01' AS DATETIME) AS monthStart
                   ,DATEADD(mm,1,CAST(CONVERT(CHAR(6),minDate,112) + '01' AS DATETIME)) -1 AS monthEnd
                   ,1 AS monthID
            FROM rangeCTE
    
            UNION ALL
    
            SELECT DATEADD(mm,1,monthStart)
                   ,DATEADD(mm,2,monthStart) - 1
                   ,monthID + 1
            FROM datelistCTE
            WHERE monthStart <= (SELECT maxDate FROM rangeCTE)
    )
    ,priceOrderCTE
    AS
    (
            SELECT * 
                   ,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
                                       ORDER BY priceDate
                                       ) AS rn1
                   ,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
                                       ORDER BY priceDate DESC
                                       ) AS rn2
                   ,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
                                       ORDER BY price DESC
                                       ) AS rn3                                   
                   ,ROW_NUMBER() OVER (PARTITION BY monthID, priceType
                                       ORDER BY price 
                                       ) AS rn4
            FROM datelistCTE AS d
            JOIN #t          AS t
            ON t.priceDate BETWEEN d.monthStart AND d.monthEnd
            WHERE monthStart <= (SELECT maxDate FROM rangeCTE)
    )
    SELECT o.MonthStart
           ,o.priceType
           ,o.Price AS opening
           ,c.price AS closing
           ,h.price AS high
           ,l.price AS low
    FROM priceOrderCTE AS o
    JOIN priceOrderCTE AS c
    ON   c.priceType = o.PriceType 
    AND  c.monthID   = o.MonthID
    JOIN priceOrderCTE AS h
    ON   h.priceType = o.PriceType 
    AND  h.monthID   = o.MonthID
    JOIN priceOrderCTE AS l
    ON   l.priceType = o.PriceType 
    AND  l.monthID   = o.MonthID
    WHERE o.rn1 = 1
    AND   c.rn2 = 1
    AND   h.rn3 = 1
    AND   l.rn4 = 1
    

    【讨论】:

    • 对不起,我不经常使用 SQL(我的 DAL 会处理)如果我错过了该月的第一天或最后几天,这也可以吗? SQL server 的 T-SQL 中没有 FIRST / LAST 之类的东西吗?
    • @Gabriël - 此代码报告基于每个月的最早/最晚日期,无论是第一天还是最后一天,但答案是否正确取决于您的业务规则。如果缺少一个月的第一天,您是否将期初值报告为该月的最早日期,还是应该结转上个月的最后一个值?这个答案将满足第一种情况,但不会满足第二种情况。扩展代码以涵盖第二种情况并非不可能。
    • @Gabriël - T-SQL 中没有直接等效于 FIRST/LAST 的方法。您的 DAL 可能会通过执行 SELECT TOP 1 ~columns~ FROM ~table~ WHERE id = ~id~ ORDER BY ~order columns~ [ASC (for first) | DESC (for last)] 返回第一个/最后一个。
    猜你喜欢
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    • 2012-12-12
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多