2013-03-13 59 views
4

我想要计算股票的3日移动平均线(实际上30天)量。 我试图得到最后3个日期条目的平均值(而不是今天-3天)。我一直在尝试用SQL Server 2012中的rownumber做些事情,但没有成功。任何人都可以帮忙。下面是一个模板模式,以及我对SQL的垃圾尝试。我有以下SQL的各种化身与分组,但仍然无法正常工作。非常感谢!移动平均PER TICKER为每一天

select dt_eod, ticker, volume 
from 
(
    select dt_eod, ticker, avg(volume) 
    row_number() over(partition by dt_eod order by max_close desc) rn 
    from mytable 
) src 
where rn >= 1 and rn <= 3 
order by dt_eod 

示例模式:

CREATE TABLE yourtable 
    ([dt_date] int, [ticker] varchar(1), [volume] int); 

INSERT INTO yourtable 
    ([dt_date], [ticker], [volume]) 
VALUES 
    (20121201, 'A', 5), 
    (20121201, 'B', 7), 
    (20121201, 'C', 6), 
    (20121202, 'A', 10), 
    (20121202, 'B', 8),  
    (20121202, 'C', 7), 
    (20121203, 'A', 10),  
    (20121203, 'B', 87),  
    (20121203, 'C', 74), 
    (20121204, 'A', 10),  
    (20121204, 'B', 86), 
    (20121204, 'C', 67), 
    (20121205, 'A', 100), 
    (20121205, 'B', 84), 
    (20121205, 'C', 70),  
    (20121206, 'A', 258), 
    (20121206, 'B', 864), 
    (20121206, 'C', 740); 
+0

如果您创建了一个包含Year和BusinessDay(从1到250左右)的Calandar表,那么您可以将它加入到它,并通过BusinesDay(getdate()) - 3到BusinesDay(getdate())进行平均。 – 2013-03-13 20:56:21

回答

3

三天平均每一行:

with top3Values as 
(
    select t.ticker, t.dt_date, top3.volume 
    from yourtable t 
    outer apply 
    (
     select top 3 top3.volume 
     from yourtable top3 
     where t.ticker = top3.ticker 
     and t.dt_date >= top3.dt_date 
     order by top3.dt_date desc 
    ) top3 
) 
select ticker, dt_date, ThreeDayVolume = avg(volume) 
from top3Values 
group by ticker, dt_date 
order by ticker, dt_date 

SQL Fiddle demo

最新值:

with tickers as 
(
    select distinct ticker from yourtable 
), top3Values as 
(
    select t.ticker, top3.volume 
    from tickers t 
    outer apply 
    (
     select top 3 top3.volume 
     from yourtable top3 
     where t.ticker = top3.ticker 
     order by dt_date desc 
    ) top3 
) 
select ticker, ThreeDayVolume = avg(volume) 
from top3Values 
group by ticker 
order by ticker 

SQL Fiddle demo

现实,你就不需要创建代号CTE第二查询,因为你会被此基础上[ticker]表,你可能会在查询某种date参数,但希望这会让你走上正轨。

+0

太棒了 - 它的作品,只需要现在就完全理解它! – SQLseeker 2013-03-13 21:50:15

+0

确实不错。但是,使用'cross apply'而不是'outer apply'会产生相同的输出,并且可能产生更好的执行计划。 – 2013-03-14 21:49:35

+0

公平点,很难避免每个人都加入到自己的行列中......在这种情况下,“外部应用”显然过于谨慎! – 2013-03-14 22:34:56

2

你提到了SQL 2012,这意味着你可以利用一个更简单的范例。

select dt_date, ticker, avg(1.0*volume) over (
    partition by ticker 
    order by dt_date 
    ROWS BETWEEN 2 preceding and current row 
) 
from yourtable 

我觉得这对于实际尝试完成的东西要透明得多。

1

你可能想看看这里介绍的另一种技术:SQL-Server Moving Averages set-based algorithm with flexible window-periods and no self-joins

该算法相当快速(比APPLY快得多,在性能上不会像APPLY那样降低数据点窗口的扩展性),可以很容易地适应您的需求,适用于pre-SQL2012,并克服了SQL的局限性-2012的窗口功能需要在OVER/PARTITION-BY子句中对窗口宽度进行硬编码。

对于具有移动价格平均一个股市类型的应用程序,它是一个常见的需求,以允许用户到变化的包括在平均(从UI选择数据点的数量,如允许用户选择7天,30天,60天等),而SQL-2012的OVER子句无法处理此变量分区宽度要求,而无需动态SQL。