OHCL (Open-high-low-close) T-SQL 查询

Posted

技术标签:

【中文标题】OHCL (Open-high-low-close) T-SQL 查询【英文标题】:OHCL (Open-high-low-close) T-SQL Query 【发布时间】:2017-11-15 14:14:38 【问题描述】:

我正在尝试对 StockData 表执行 OHCL sql 查询 (SQL Server 2012)。每天有数千行添加到表中,我想获取每天的开盘价、最高价、最低价和收盘价数据。

创建表sql如下:

  CREATE TABLE [dbo].[StockData](
    [ID] [bigint] IDENTITY(1,1) NOT NULL,
    [StockExchangeID] [bigint] NOT NULL,
    [DataDateTime] [datetime] NOT NULL,
    [ExportCost] [bigint] NOT NULL,
 CONSTRAINT [PK_StockData] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

使用下面的查询,我可以获得最高、最低和平均,但我很难获得当天 ExportCost 的打开(基于 DataDateTime 的最早 ExportCost)和关闭(基于 DataDateTime 的最新 ExportCost)。

到目前为止,我的查询如下。如果有更有效的方法,欢迎提出任何建议。

DECLARE @IntervalDays INT, @StartDate DATETIME, @EndDate DATETIME;
SET @IntervalDays = 1;
SET @StartDate = '01/01/2017'
SET @EndDate = '01/01/2018'

-- Create the database table
SELECT 
    StockExchangeID,
    DATEADD(DAY, DATEDIFF(DAY,0,[DataDateTime]) / @IntervalDays * @IntervalDays, 0) AS [DateDay],
    MAX(ExportCost) AS DayHigh, 
    MIN(ExportCost) AS DayLow, 
    AVG(ExportCost) AS DayAverage,
    '??????????' As DayOpen, --Not sure how to get the start price for the day i.e. ExportCost for the first record for that day based on [DataDateTime]
    '??????????' As DatClose
FROM StockData
WHERE [DataDateTime] >= @StartDate AND [DataDateTime] <= @EndDate
GROUP BY DATEADD(DAY, DATEDIFF(DAY,0,[DataDateTime]) / @IntervalDays * @IntervalDays, 0), StockExchangeID
ORDER BY [DateDay]

【问题讨论】:

哪个版本的sql server? / @IntervalDays * @IntervalDays 应该达到什么目的? Sql-server 2012 及更高版本支持 FIRST_VALUE、LAST_VALUE。检查答案***.com/questions/41840829/… 以查看 GROUP BY 的用法 SQL Server 2012. 【参考方案1】:

对于旧版本的 SQL Server 使用可以使用相关子查询:

SELECT 
    StockExchangeID,
    DATEADD(DAY, DATEDIFF(DAY,0,[DataDateTime]) / @IntervalDays * @IntervalDays, 0) AS [DateDay],
    MAX(ExportCost) AS DayHigh, 
    MIN(ExportCost) AS DayLow, 
    AVG(ExportCost) AS DayAverage,
    (SELECT TOP 1 DO.ExportCost FROM StockData AS DO WHERE DO.[DataDateTime] = MIN( A.[DataDateTime] ) ORDER BY ID ASC ) As DayOpen, 
    (SELECT TOP 1 DC.ExportCost FROM StockData AS DC WHERE DC.[DataDateTime] = MAX( A.[DataDateTime] ) ORDER BY ID DESC ) As DatClose
FROM StockData AS A
WHERE [DataDateTime] >= @StartDate AND [DataDateTime] <= @EndDate
GROUP BY DATEADD(DAY, DATEDIFF(DAY,0,[DataDateTime]) / @IntervalDays * @IntervalDays, 0), StockExchangeID
ORDER BY [DateDay]

注意: Order By ID 用于防止您有超过 1 条具有相同日期的记录。

对于较新的版本,请查看@Serg 关于FIRST_VALUE 的评论

【讨论】:

这提供了正确的结果 - 谢谢。如果表中有很多行,CTE 或其他替代查询会使其更高效吗? 你最大的表现违规者将是GROUP BY DATEADD(DAY, DATEDIFF(DAY,0,[DataDateTime]) / @IntervalDays * @IntervalDays, 0)。你仍然没有回复我原来的评论,为什么你乘以同一个变量然后除以相同的变量。 Alex - 我从另一个查询中复制了那段代码,我已经拆分并将库存时间分组为每天 15 分钟的间隔。因为它是我当前的查询,它什么都不做,我将删除它。【参考方案2】:

相信我 - 您可能希望保留此级别的详细数据,但不想将其用于一般报告目的。您需要将定价汇总为每天的最高/最低/收盘/开盘价并存储它们,因为它们在交易日结束后不会改变(嗯,有时它们会改变,但这种情况非常罕见并且不会改变一般方法)。

更进一步 - 您选择的主键和聚集索引可能不是特别有用。您几乎总是在此表中搜索给定证券或给定日期(或日期范围)。在标识列上进行聚类可能很浪费。我还会考虑将日期和时间分成单独的列。日期部分非常重要——时间部分可能用的不多。如果您要将日期和时间分开,您的查询会变得更加简单,因为您只需按日期分组即可找到最小值/最大值。通过额外的架构更改(或更好 - 使用交易后聚合表)可以简化查找打开和关闭。

【讨论】:

我意识到这一点,但现在我正在制作原型,我需要一些快速而肮脏的东西。我们确实设想了一个计划的作业/服务将聚合数据推送到历史表以便更好地查询。无论哪种方式,我仍然需要解决查询。谢谢大家!

以上是关于OHCL (Open-high-low-close) T-SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

比较Pandas系列中的先前值和下一个值