postgresql для в l oop оператора select - проблема с обновлением переменной с помощью итераций - PullRequest
0 голосов
/ 30 апреля 2020

Я написал функцию для вычисления экспоненциальной скользящей средней для цен, которая перебирает результаты оператора SELECT. Длина скользящей средней составляет 26 дней. Для первых 25 строк значение EMA равно нулю. 26-й день - это просто среднее значение первых 26 значений. Любая строка после 26 имеет значение EMA (текущая цена строки - предыдущая строка EMA) * (2/27) + previous_row_EMA.

Ниже l oop делает это с помощью операторов CASE. Я объявил переменную "sumlong" и установил ее в ноль. Переменная sumlong хранит текущее суммирование первых 25 строк. Второй оператор CASE вычисляет простое скользящее среднее за 26 дней. Я также объявил переменную «last_EMA26» в качестве временного держателя для использования в следующей итерации.

Кажется, что 26-я строка рассчитывается правильно, однако любая строка после 26-й строки, похоже, не содержит вычисления и использует то же значение, что и 26-я строка. Есть идеи, что я делаю не так? Не стесняйтесь оставлять отзывы о том, как я мог бы сделать этот код более эффективным. Я уверен, что это не самый эффективный способ, но я учусь.

CREATE OR REPLACE FUNCTION MACD()
    RETURNS TABLE(
        _ID INTEGER,
        _CUSIP TEXT,
        _DATETIME TIMESTAMP WITHOUT TIME ZONE,
        _PCLOSE NUMERIC,
        _ROWNUM BIGINT,
        _EMAL NUMERIC
    )
AS $$
DECLARE 
    sumlong numeric := 0.00;
    sumshort numeric := 0.00;
    last_ema26 numeric := 0.00;
BEGIN
    FOR _ID, _CUSIP, _DATETIME, _PCLOSE, _ROWNUM IN
    SELECT ID, CUSIP, datetime, pclose, k
        FROM
        (SELECT ID, CUSIP, datetime, (dhist::json->>'close')::numeric AS pclose, ROW_NUMBER () OVER(w) as K 
        FROM dailyhist
        WHERE cusip = '00130H105'
        WINDOW w AS (PARTITION BY CUSIP ORDER BY datetime)
        ) EMA
    LOOP
        CASE
            WHEN _ROWNUM < 26 THEN
                _EMAL := NULL;
                sumlong := sumlong + _PCLOSE;
                 RAISE NOTICE '1 counter is: %,  row: %, close: %  emal: %, lastema: %', sumlong, _ROWNUM, _PCLOSE, _EMAL, last_ema26;
            WHEN _ROWNUM = 26 THEN
                _EMAL:= (sumlong + _PCLOSE)/26;
                last_ema26 := _EMAL;
                RAISE NOTICE '2 counter is: %,  row: %, close: %  emal: %, lastema: %', sumlong, _ROWNUM, _PCLOSE, _EMAL, last_ema26;
            WHEN _ROWNUM > 26 THEN
                _EMAL = (_PCLOSE - last_ema26)*(2/27) + last_ema26;
                last_ema26 := _EMAL;
                RAISE NOTICE '3 counter is: %,  row: %, close: %  emal: %, lastema: %', sumlong, _ROWNUM, _PCLOSE, _EMAL, last_ema26;
        END CASE;
        RETURN NEXT;    
    END LOOP;
END;$$
LANGUAGE 'plpgsql';

SELECT * FROM MACD();

Я также включил часть вывода:

NOTICE:  1 counter is: 3.37517,  row: 1, close: 3.37517  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 6.79201,  row: 2, close: 3.41684  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 10.18801,  row: 3, close: 3.396  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 13.60485,  row: 4, close: 3.41684  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 17.06336,  row: 5, close: 3.45851  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 20.48020,  row: 6, close: 3.41684  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 23.77203,  row: 7, close: 3.29183  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 27.06386,  row: 8, close: 3.29183  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 30.60570,  row: 9, close: 3.54184  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 34.43922,  row: 10, close: 3.83352  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 38.33525,  row: 11, close: 3.89603  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 42.16877,  row: 12, close: 3.83352  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 46.00229,  row: 13, close: 3.83352  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 50.04416,  row: 14, close: 4.04187  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 54.29437,  row: 15, close: 4.25021  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 58.54458,  row: 16, close: 4.25021  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 62.58645,  row: 17, close: 4.04187  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 66.62832,  row: 18, close: 4.04187  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 70.48268,  row: 19, close: 3.85436  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 74.23287,  row: 20, close: 3.75019  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 77.94139,  row: 21, close: 3.70852  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 81.69158,  row: 22, close: 3.75019  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 85.48344,  row: 23, close: 3.79186  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 89.56698,  row: 24, close: 4.08354  emal: <NULL>, lastema: <NULL>
NOTICE:  1 counter is: 93.73385,  row: 25, close: 4.16687  emal: <NULL>, lastema: <NULL>
NOTICE:  2 counter is: 93.73385,  row: 26, close: 4.20854  emal: 3.7670150000000000, lastema: 3.7670150000000000
NOTICE:  3 counter is: 93.73385,  row: 27, close: 4.16687  emal: 3.7670150000000000, lastema: 3.7670150000000000
NOTICE:  3 counter is: 93.73385,  row: 28, close: 4.08354  emal: 3.7670150000000000, lastema: 3.7670150000000000
NOTICE:  3 counter is: 93.73385,  row: 29, close: 4.12521  emal: 3.7670150000000000, lastema: 3.7670150000000000
NOTICE:  3 counter is: 93.73385,  row: 30, close: 4.12521  emal: 3.7670150000000000, lastema: 3.7670150000000000
NOTICE:  3 counter is: 93.73385,  row: 31, close: 4.12521  emal: 3.7670150000000000, lastema: 3.7670150000000000
NOTICE:  3 counter is: 93.73385,  row: 32, close: 4.0627  emal: 3.7670150000000000, lastema: 3.7670150000000000

1 Ответ

0 голосов
/ 30 апреля 2020

Я не уверен, в чем проблема, но я вижу одну, вероятно, неправильную точку в выражении:

_EMAL = (_PCLOSE - last_ema26)*(2/27) + last_ema26;

Postgres по умолчанию использовать целочисленное деление для целых чисел. Вероятно, 2/27 не возвращает того, что вы ожидаете

postgres=# select 2/27;
┌──────────┐
│ ?column? │
╞══════════╡
│        0 │
└──────────┘
 (1 row)

Если вы хотите вычислить какое-то отношение, то вам не следует использовать целочисленные константы

postgres=# select 2.0/27.0;
┌────────────────────────┐
│        ?column?        │
╞════════════════════════╡
│ 0.07407407407407407407 │
└────────────────────────┘
(1 row)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...