Исключить ноль или нули в расчете среднего за предыдущие торговые дни - PullRequest
1 голос
/ 24 октября 2019

Я думал, что понял, но на самом деле нет. Работа с некоторыми торговыми данными и необходимо сделать среднюю цену акций только за торговые дни. Использовал приведенный ниже запрос для среднего значения за 3 дня;но недавно выяснилось, что в торговый отпуск могут быть дивиденды;поэтому для тех дней в таблице фактов есть данные для биржевого кода и closeprice либо ноль, либо ноль.

Пожалуйста, помогите мне улучшить мой запрос, чтобы игнорировать ноль и нули в среднем вычислении за 3 предшествующих торговых дня

select StockCode, datekey, ClosePrice, 
AVG(ClosePrice) OVER (partition by StockCode order by datekey 
ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING) Avg3Days
from Fact

Ответы [ 2 ]

1 голос
/ 24 октября 2019

Вы можете разделить на StockCode И sign(NullIf([ClosePrice],0)) вместо необходимости знать торговые дни.

Пример

Declare @YourTable Table ([datekey] date,[StockCode] varchar(50),[ClosePrice] money)  
Insert Into @YourTable Values 
 ('2019-06-15','xyx',5)
,('2019-06-16','xyx',10)
,('2019-06-17','xyx',NULL)
,('2019-06-18','xyx',0)
,('2019-06-19','xyx',15)
,('2019-06-20','xyx',20)

Select * 
     ,AvgPrice = AVG(ClosePrice) over (partition by StockCode,sign(NullIf([ClosePrice],0)) order By datekey rows between 3 preceding and 1 preceding  )      
from @YourTable
Order By datekey

Возврат

datekey     StockCode   ClosePrice  AvgPrice
2019-06-15  xyx         5.00        NULL
2019-06-16  xyx         10.00       5.00
2019-06-17  xyx         NULL        NULL
2019-06-18  xyx         0.00        NULL
2019-06-19  xyx         15.00       7.50
2019-06-20  xyx         20.00       10.00

Обновление

Немного страшнее, но, возможно, что-то вроде этого

Select * 
     ,AvgPrice = case when sum(1)          over (partition by StockCode,sign(NullIf([ClosePrice],0)) order By datekey rows between 3 preceding and 1 preceding  ) = 3
                      then avg(ClosePrice) over (partition by StockCode,sign(NullIf([ClosePrice],0)) order By datekey rows between 3 preceding and 1 preceding  )      
                      else null end
from @YourTable
Order By datekey

Возвращает

enter image description here

1 голос
/ 24 октября 2019

Предполагая, что у вас есть флаг, который указывает торговые дни, вы можете сделать что-то вроде этого:

SELECT StockCode, datekey, ClosePrice, 
       (CASE WHEN isTradingDay = 1
             THEN AVG(ClosePrice) OVER (PARTITION BY StockCode, isTradingDay
                                        ORDER BY datekey 
                                        ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING
                                       )
        END) as Avg3Days
FROM Fact;

Это занимает среднее значение за предыдущие три торговых дня. Значение составляет NULL в неторговые дни.

Если StockCode равно NULL, оно все равно не будет включено в среднее значение. Если единственным индикатором является closePrice, то один метод:

SELECT f.StockCode, f.datekey, f.ClosePrice, 
       (CASE WHEN v.isTradingDay = 1
             THEN AVG(f.ClosePrice) OVER (PARTITION BY f.StockCode, v.isTradingDay
                                          ORDER BY f.datekey 
                                          ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING
                                         )
        END) as Avg3Days
FROM Fact f CROSS APPLY
     (VALUES (CASE WHEN f.ClosePrice > 0 THEN 1 ELSE 0 END)
     ) v(isTradingDay);

Лично я предпочел бы иметь явный индикатор торгового дня, а не полагаться на специальные значения цены закрытия. Например, торговля по одной акции может быть приостановлена ​​по какой-то специфической для компании причине.

Возможно, вы также захотите иметь WHERE f.StockCode <> '' для фильтрации недействительных кодов акций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...