Changes between Version 3 and Version 4 of otherdevelopment


Ignore:
Timestamp:
03/04/26 21:40:01 (2 weeks ago)
Author:
231020
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • otherdevelopment

    v3 v4  
    201201'''SQL:'''
    202202{{{
    203 -- Core query inside report_stock_volatility_and_activity()
    204 WITH daily_returns AS (
    205     SELECT sh.stock_id AS dr_stock_id,
    206            sh.price    AS dr_price,
    207            (sh.price - LAG(sh.price) OVER (
    208                PARTITION BY sh.stock_id ORDER BY sh.timestamp))
    209            / NULLIF(LAG(sh.price) OVER (
    210                PARTITION BY sh.stock_id ORDER BY sh.timestamp), 0)
    211            AS dr_daily_return
    212     FROM stock_history sh
    213     WHERE sh.timestamp >= p_from_date
    214       AND sh.timestamp <= p_to_date
    215 ),
    216 price_stats AS (
    217     SELECT dr.dr_stock_id,
    218            COUNT(*)  AS ps_total_points,
    219            MIN(dr.dr_price) AS ps_min_price,
    220            MAX(dr.dr_price) AS ps_max_price,
    221            AVG(dr.dr_price) AS ps_avg_price,
    222            COALESCE(STDDEV(dr.dr_daily_return) * 100, 0) AS ps_volatility_pct
    223     FROM daily_returns dr
    224     GROUP BY dr.dr_stock_id
    225 ),
    226 txn_stats AS (
    227     SELECT t.stock_id AS ts_stock_id,
    228            SUM(t.price * t.quantity)                 AS ts_total_volume,
    229            COUNT(*)                                  AS ts_total_count,
    230            COUNT(*) FILTER (WHERE t.type = 'BUY')   AS ts_buy_count,
    231            COUNT(*) FILTER (WHERE t.type = 'SELL')  AS ts_sell_count
    232     FROM transactions t
    233     WHERE t.timestamp >= p_from_date
    234       AND t.timestamp <= p_to_date
    235     GROUP BY t.stock_id
     203CREATE OR REPLACE FUNCTION report_stock_volatility_and_activity(
     204    p_from_date TIMESTAMP DEFAULT NULL,
     205    p_to_date   TIMESTAMP DEFAULT NULL
    236206)
    237 SELECT s.id, s.symbol, s.name, s.current_price, ...
    238 FROM stock s
    239 LEFT JOIN price_stats ps ON s.id = ps.dr_stock_id
    240 LEFT JOIN txn_stats   ts ON s.id = ts.ts_stock_id
    241 ORDER BY historical_volatility_pct DESC, activity_score DESC;
     207    RETURNS TABLE (
     208        stock_id                  INTEGER,
     209        symbol                    TEXT,
     210        stock_name                TEXT,
     211        current_price             NUMERIC,
     212        period_min_price          NUMERIC,
     213        period_max_price          NUMERIC,
     214        price_range_pct           NUMERIC,
     215        avg_daily_price           NUMERIC,
     216        historical_volatility_pct NUMERIC,
     217        total_history_points      BIGINT,
     218        total_txn_volume          NUMERIC,
     219        total_txn_count           BIGINT,
     220        buy_txn_count             BIGINT,
     221        sell_txn_count            BIGINT,
     222        buy_sell_ratio            NUMERIC,
     223        active_watchlist_users    BIGINT,
     224        pending_trade_requests    BIGINT,
     225        trend_direction           TEXT,
     226        trend_slope               NUMERIC,
     227        activity_score            NUMERIC,
     228        volatility_rank           BIGINT,
     229        activity_rank             BIGINT
     230    ) AS $$
     231BEGIN
     232    RETURN QUERY
     233        WITH
     234        -- Volatility: stddev of daily returns computed with LAG window function
     235        -- computing daily return per row using LAG window function
     236        daily_returns AS (
     237            SELECT
     238                sh.stock_id                AS dr_stock_id,
     239                sh.price                   AS dr_price,
     240                (sh.price - LAG(sh.price) OVER (
     241                    PARTITION BY sh.stock_id ORDER BY sh.timestamp
     242                )) / NULLIF(LAG(sh.price) OVER (
     243                    PARTITION BY sh.stock_id ORDER BY sh.timestamp
     244                ), 0)                      AS dr_daily_return
     245            FROM stock_history sh
     246            WHERE (p_from_date IS NULL OR sh.timestamp >= p_from_date)
     247              AND (p_to_date   IS NULL OR sh.timestamp <= p_to_date)
     248        ),
     249        -- aggregate per stock
     250        price_stats AS (
     251            SELECT
     252                dr.dr_stock_id             AS ps_stock_id,
     253                COUNT(*)                   AS ps_total_points,
     254                MIN(dr.dr_price)           AS ps_min_price,
     255                MAX(dr.dr_price)           AS ps_max_price,
     256                AVG(dr.dr_price)           AS ps_avg_price,
     257                COALESCE(STDDEV(dr.dr_daily_return) * 100, 0) AS ps_volatility_pct
     258            FROM daily_returns dr
     259            GROUP BY dr.dr_stock_id
     260        ),
     261        -- trend least-squares linear regression slope on (row_number, price)
     262     
     263        price_ordered AS (
     264            SELECT
     265                sh.stock_id            AS po_stock_id,
     266                ROW_NUMBER() OVER (PARTITION BY sh.stock_id ORDER BY sh.timestamp) AS po_rn,
     267                sh.price                   AS po_price
     268            FROM stock_history sh
     269            WHERE (p_from_date IS NULL OR sh.timestamp >= p_from_date)
     270              AND (p_to_date   IS NULL OR sh.timestamp <= p_to_date)
     271        ),
     272        trend_calc AS (
     273            SELECT
     274                po.po_stock_id             AS tc_stock_id,
     275                ROUND(
     276                    ((COUNT(*) * SUM(po.po_rn * po.po_price) - SUM(po.po_rn) * SUM(po.po_price))
     277                    / NULLIF(COUNT(*) * SUM(po.po_rn * po.po_rn) - SUM(po.po_rn) * SUM(po.po_rn), 0))::NUMERIC
     278                , 6)                       AS tc_slope
     279            FROM price_ordered po
     280            GROUP BY po.po_stock_id
     281        ),
     282        -- transctikomn stats per stock in period
     283        txn_stats AS (
     284            SELECT
     285                t.stock_id                 AS ts_stock_id,
     286                SUM(t.price * t.quantity)  AS ts_total_volume,
     287                COUNT(*)                   AS ts_total_count,
     288                COUNT(*) FILTER (WHERE t.type = 'BUY')  AS ts_buy_count,
     289                COUNT(*) FILTER (WHERE t.type = 'SELL') AS ts_sell_count
     290            FROM transactions t
     291            WHERE (p_from_date IS NULL OR t.timestamp >= p_from_date)
     292              AND (p_to_date   IS NULL OR t.timestamp <= p_to_date)
     293            GROUP BY t.stock_id
     294        ),
     295        -- watchlist interest  stock
     296        watchlist_stats AS (
     297            SELECT
     298                w.stock_id                 AS ws_stock_id,
     299                COUNT(DISTINCT w.user_id)  AS ws_active_watchers
     300            FROM watchlist w
     301            GROUP BY w.stock_id
     302        ),
     303        -- pending trade requests per stock
     304        pending_stats AS (
     305            SELECT
     306                s.id                       AS pst_stock_id,
     307                COUNT(tr.id)               AS pst_pending_count
     308            FROM trade_request tr
     309            JOIN stock s ON tr.stock_symbol = s.symbol
     310            WHERE tr.status = 'PENDING'
     311            GROUP BY s.id
     312        )
     313
     314        SELECT
     315            s.id::INTEGER                                                AS stock_id,
     316            s.symbol::TEXT,
     317            s.name::TEXT                                                 AS stock_name,
     318            s.current_price::NUMERIC,
     319            COALESCE(ps.ps_min_price, s.current_price)::NUMERIC         AS period_min_price,
     320            COALESCE(ps.ps_max_price, s.current_price)::NUMERIC         AS period_max_price,
     321            ROUND(
     322                ((COALESCE(ps.ps_max_price, s.current_price)
     323                 - COALESCE(ps.ps_min_price, s.current_price))
     324                / NULLIF(COALESCE(ps.ps_min_price, s.current_price), 0) * 100)::NUMERIC
     325            , 2)::NUMERIC                                                AS price_range_pct,
     326            COALESCE(ps.ps_avg_price, s.current_price)::NUMERIC         AS avg_daily_price,
     327            COALESCE(ps.ps_volatility_pct, 0)::NUMERIC                  AS historical_volatility_pct,
     328            COALESCE(ps.ps_total_points, 0)::BIGINT                     AS total_history_points,
     329            COALESCE(ts.ts_total_volume, 0)::NUMERIC                    AS total_txn_volume,
     330            COALESCE(ts.ts_total_count,  0)::BIGINT                     AS total_txn_count,
     331            COALESCE(ts.ts_buy_count,    0)::BIGINT                     AS buy_txn_count,
     332            COALESCE(ts.ts_sell_count,   0)::BIGINT                     AS sell_txn_count,
     333            ROUND(
     334                (COALESCE(ts.ts_buy_count, 0)::NUMERIC
     335                / NULLIF(COALESCE(ts.ts_sell_count, 0), 0))::NUMERIC
     336            , 2)::NUMERIC                                                AS buy_sell_ratio,
     337            COALESCE(ws.ws_active_watchers, 0)::BIGINT                  AS active_watchlist_users,
     338            COALESCE(pst.pst_pending_count, 0)::BIGINT                  AS pending_trade_requests,
     339            CASE
     340                WHEN tc.tc_slope >  0.01 THEN 'UPTREND'
     341                WHEN tc.tc_slope < -0.01 THEN 'DOWNTREND'
     342                ELSE                          'SIDEWAYS'
     343            END::TEXT                                                    AS trend_direction,
     344            COALESCE(tc.tc_slope, 0)::NUMERIC                           AS trend_slope,
     345            ROUND(
     346                (COALESCE(ws.ws_active_watchers, 0) * 2.0
     347                + COALESCE(ts.ts_total_count,    0) * 1.0
     348                + COALESCE(pst.pst_pending_count, 0) * 3.0)::NUMERIC
     349            , 2)::NUMERIC                                                AS activity_score,
     350            RANK() OVER (
     351                ORDER BY COALESCE(ps.ps_volatility_pct, 0) DESC
     352            )::BIGINT                                                    AS volatility_rank,
     353            RANK() OVER (
     354                ORDER BY (
     355                    COALESCE(ws.ws_active_watchers, 0) * 2.0
     356                    + COALESCE(ts.ts_total_count,    0) * 1.0
     357                    + COALESCE(pst.pst_pending_count, 0) * 3.0
     358                ) DESC
     359            )::BIGINT                                                    AS activity_rank
     360        FROM stock s
     361        LEFT JOIN price_stats     ps  ON s.id = ps.ps_stock_id
     362        LEFT JOIN trend_calc      tc  ON s.id = tc.tc_stock_id
     363        LEFT JOIN txn_stats       ts  ON s.id = ts.ts_stock_id
     364        LEFT JOIN watchlist_stats ws  ON s.id = ws.ws_stock_id
     365        LEFT JOIN pending_stats   pst ON s.id = pst.pst_stock_id
     366        ORDER BY historical_volatility_pct DESC, activity_score DESC;
     367END;
     368$$ LANGUAGE plpgsql;
    242369}}}
    243370
     
    246373'''EXPLAIN ANALYZE без индекси:'''
    247374{{{
    248 EXPLAIN ANALYZE
    249 SELECT sh.stock_id, sh.price, sh.timestamp
    250 FROM stock_history sh
    251 WHERE sh.timestamp >= '2024-01-01'
    252   AND sh.timestamp <= '2024-12-31'
    253 ORDER BY sh.stock_id, sh.timestamp;
    254 
     375EXPLAIN ANALYZE SELECT * FROM report_stock_volatility_and_activity('2024-01-01', '2024-12-31');
    255376-- резултат:
    256 Sort  (cost=31.85..31.87 rows=7 width=20) (actual time=0.051..0.052 rows=0 loops=1)
    257   Sort Key: stock_id, "timestamp"
    258   Sort Method: quicksort  Memory: 25kB
    259   ->  Seq Scan on stock_history sh  (cost=0.00..31.75 rows=7 width=20) (actual time=0.018..0.018 rows=0 loops=1)
    260         Filter: (("timestamp" >= '2024-01-01'::date) AND ("timestamp" <= '2024-12-31'::date))
    261         Rows Removed by Filter: 8
    262 Planning Time: 0.417 ms
    263 Execution Time: 0.077 ms
     377QUERY PLAN                                                                                                                               |
     378-----------------------------------------------------------------------------------------------------------------------------------------+
     379Function Scan on report_stock_volatility_and_activity  (cost=0.25..10.25 rows=1000 width=484) (actual time=13.601..13.602 rows=4 loops=1)|
     380Planning Time: 0.094 ms                                                                                                                  |
     381Execution Time: 15.248 ms                                                                                                                |
    264382}}}
    265383
     
    313431'''EXPLAIN ANALYZE со индекси:'''
    314432{{{
    315 EXPLAIN ANALYZE
    316 SELECT sh.stock_id, sh.price, sh.timestamp
    317 FROM stock_history sh
    318 WHERE sh.timestamp >= '2024-01-01'
    319   AND sh.timestamp <= '2024-12-31'
    320 ORDER BY sh.stock_id, sh.timestamp;
    321 
     433EXPLAIN ANALYZE SELECT * FROM report_stock_volatility_and_activity('2024-01-01', '2024-12-31');
    322434-- резултат:
    323 Sort  (cost=1.13..1.14 rows=1 width=20) (actual time=0.024..0.025 rows=0 loops=1)
    324   Sort Key: stock_id, "timestamp"
    325   Sort Method: quicksort  Memory: 25kB
    326   ->  Seq Scan on stock_history sh  (cost=0.00..1.12 rows=1 width=20) (actual time=0.017..0.017 rows=0 loops=1)
    327         Filter: (("timestamp" >= '2024-01-01'::date) AND ("timestamp" <= '2024-12-31'::date))
    328         Rows Removed by Filter: 8
    329 Planning Time: 0.397 ms
    330 Execution Time: 0.054 ms
     435QUERY PLAN                                                                                                                             |
     436---------------------------------------------------------------------------------------------------------------------------------------+
     437Function Scan on report_stock_volatility_and_activity  (cost=0.25..10.25 rows=1000 width=484) (actual time=6.624..6.625 rows=4 loops=1)|
     438Planning Time: 0.111 ms                                                                                                                |
     439Execution Time: 6.693 ms                                                                                                               |
    331440}}}
    332441