поиск локальных максимумов и локальных минимумов в SQL - PullRequest
1 голос
/ 28 октября 2010

Чтобы найти максимальную просадку графика цены акций в зависимости от времени, сначала необходимо найти все локальные максимумы (пики) и локальные минимумы (долины) для заданного набора цен и дней.Как бы вы сделали это в SQL Server 2005?

edit: Существует простой способ сделать это с помощью курсоров: сравнить максимум первого дня с максимумом следующего дня.если максимум первого дня выше максимума следующего дня, максимум первого дня фактически является локальным максимумом

, мне нужно найти каждую точку, на которой тренд графика ценыизменяет направление.

edit2: я должен отметить, что таблица базы данных для работы имеет следующие столбцы:

stockid int
дата дня
hi int --thisв пенни
low int - также в пенни
, поэтому для данного диапазона дат вы будете видеть один и тот же запас каждый день для этого диапазона дат.

Ответы [ 2 ]

1 голос
/ 28 октября 2010

Хорошо, пошагово вот что я думаю:

1 - Найдите все ваши "пики", которые являются максимальными значениями с максимальными значениями LOWER на следующий день:

DECLARE @HiTable (hi int, day date)

INSERT INTO @HiTable
SELECT hi, day
FROM table t1
WHERE EXISTS (
 SELECT t2.hi
 FROM Table t2
 WHERE t1.hi > t2.hi AND t1.day < t2.day and StockID = X)

2 - Найдите все ваши «долины», которые являются минимальными значениями, с HIGHER min значениями на следующий день:

DECLARE @LowTable (low int, day date)

INSERT INTO @LowTable
SELECT low, day
FROM table t1
WHERE EXISTS (
 SELECT t2.low
 FROM Table t2
 WHERE t1.low < t2.low AND t1.day < t2.day and StockID = X)

3 - Объедините их в таблицу, упорядоченную по дате, со значением идентичности, чтобы держать нас в порядке

DECLARE @TableVar (low int, hi int, day date, autoid int IDENTITY)
INSERT INTO @TableVar
(SELECT low, hi, day
FROM (
 SELECT Low, NULL as 'hi', date FROM @LowTable
 UNION ALL
 SELECT NULL as 'Low', hi, date FROM @HiTable
 )
ORDER BY DATE)

4 - Удалить выбросы

DELETE FROM @TableVar WHERE AutoID > (SELECT MAX(AutoID) FROM @Table WHERE low IS NULL)
DELETE FROM @TableVar WHERE AutoID < (SELECT MIN(AutoID) FROM @Table WHERE hi IS NULL)
0 голосов
/ 29 октября 2010

Предположительно, не проверено полностью - но как насчет использования CTE и ROWNUMBER (), чтобы сделать это в два этапа

1) Определите все nextsubseqent hi для каждого ряда 2) любая строка, следующая непосредственно за следующей строкой, имеет последующий максимум меньше текущей строки - тогда текущая строка должна иметь локальный максимум.

или что-то в этом роде:

begin 
    DECLARE  @highTable as table (high bigint, day date)

    declare @securityid int,
    @start datetime,
    @end datetime

    set @start = '1-1-2010'
    set @end = '2-1-2010'   
    select @securityid = id from security where riccode = 'MSFT.OQ' ;

    with highsandlows_cte as (
        SELECT 
            ROW_NUMBER() over (order by day) i
            , high
            , day
            , (select top 1 day from quotes nextHi where nextHi.high > today.high and nextHi.day >= today.day and nextHi.securityId = today.securityId order by day asc) nextHighestDay

        FROM 
            quotes today
        WHERE 
            today.securityid = @securityid )

    select 
        * 
        , (Coalesce((select 1 from highsandlows_cte t2 where t1.i + 1  = t2.i and t1.nextHighestDay > t2.nextHighestDay),0))  as isHigh
    from 
        highsandlows_cte t1

    order by 
        day
end

хорошо, вышеприведенное неверно - похоже, это больше на пути:

begin 
      DECLARE  @highTable as table (high bigint, day date)

      declare @securityid int,
    @start datetime,
    @end datetime

      set @start = '1-1-2010'
      set @end = '2-1-2010'   
      select @securityid = id from security where riccode = 'MSFT.OQ' ;



      with highsandlows_cte as (
            SELECT 
                  ROW_NUMBER() over (order by day) i
                  , high
                  , day
                  , low
            FROM 
                  quote today
            WHERE 
                  today.securityid = @securityid and today.day > convert(varchar(10), @start, 111) and convert(varchar(10), @end, 111) >today.day)



 select
             cur.day
            , cur.high
            , cur.low
        , case when ((cur.high > prv.high or prv.high IS null)and(cur.high > nxt.high or nxt.high is null)) then 1 else 0 end as isLocalMax
        , case when ((cur.low < prv.low or prv.low IS null)and(cur.low < nxt.low or nxt.low is null)) then 1 else 0 end as isLocalMin
  from 
        highsandlows_cte cur left outer join highsandlows_cte nxt
                on  cur.i + 1  = nxt.i
            left outer join highsandlows_cte prv
                on  cur.i - 1  = prv.i
  order by 
        cur.day
end

Получите проблемы с дубликатами (максимумами / минимумами), хотя ...

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