diff --git a/kustomize/base/initdb/001_init.sql b/kustomize/base/initdb/001_init.sql index 349e8bc..fc6c900 100644 --- a/kustomize/base/initdb/001_init.sql +++ b/kustomize/base/initdb/001_init.sql @@ -162,10 +162,12 @@ RETURNS SETOF public.drift_candles LANGUAGE sql STABLE AS $$ + -- Zwraca zawsze "ciągłe" buckety (fill forward), nawet jeśli nie było ticków w danej sekundzie/minucie. + -- Dzięki temu frontend może rysować regularną oś czasu (np. 1px = 1s) bez dziwnych przeskoków. WITH src AS ( SELECT COALESCE(p_source, '') AS source_key ), - cached AS ( + raw_cached AS ( SELECT c.bucket, c.open, @@ -181,7 +183,7 @@ AS $$ ORDER BY c.bucket DESC LIMIT p_limit ), - fallback AS ( + raw_fallback AS ( SELECT time_bucket(make_interval(secs => p_bucket_seconds), ts) AS bucket, ts, @@ -201,13 +203,88 @@ AS $$ (array_agg(px ORDER BY ts DESC))[1] AS close, (array_agg(oracle_px ORDER BY ts DESC))[1] AS oracle_close, count(*) AS ticks - FROM fallback + FROM raw_fallback GROUP BY bucket + ), + data AS ( + SELECT * FROM raw_cached + UNION ALL + SELECT * FROM computed + WHERE NOT EXISTS (SELECT 1 FROM raw_cached) + ), + bounds AS ( + SELECT max(bucket) AS end_bucket FROM data + ), + params AS ( + SELECT + make_interval(secs => p_bucket_seconds) AS step, + make_interval(secs => (p_bucket_seconds * (p_limit - 1))) AS span + ), + series AS ( + SELECT generate_series( + bounds.end_bucket - params.span, + bounds.end_bucket, + params.step + ) AS bucket + FROM bounds, params + WHERE bounds.end_bucket IS NOT NULL + ), + joined AS ( + SELECT + s.bucket, + d.open, + d.high, + d.low, + d.close, + d.oracle_close, + d.ticks + FROM series s + LEFT JOIN data d USING (bucket) + ORDER BY s.bucket ASC + ), + grouped AS ( + SELECT + *, + sum(CASE WHEN close IS NOT NULL THEN 1 ELSE 0 END) OVER (ORDER BY bucket ASC) AS grp_close, + sum(CASE WHEN oracle_close IS NOT NULL THEN 1 ELSE 0 END) OVER (ORDER BY bucket ASC) AS grp_oracle + FROM joined + ), + first_vals AS ( + SELECT + (SELECT close FROM grouped WHERE close IS NOT NULL ORDER BY bucket ASC LIMIT 1) AS first_close, + (SELECT oracle_close FROM grouped WHERE oracle_close IS NOT NULL ORDER BY bucket ASC LIMIT 1) AS first_oracle + ), + ff AS ( + SELECT + g.bucket, + g.open, + g.high, + g.low, + g.close, + g.oracle_close, + g.ticks, + COALESCE( + g.close, + max(g.close) OVER (PARTITION BY g.grp_close), + f.first_close + ) AS ff_close, + COALESCE( + g.oracle_close, + max(g.oracle_close) OVER (PARTITION BY g.grp_oracle), + f.first_oracle + ) AS ff_oracle + FROM grouped g + CROSS JOIN first_vals f ) - SELECT * FROM cached - UNION ALL - SELECT * FROM computed - WHERE NOT EXISTS (SELECT 1 FROM cached) + SELECT + bucket, + COALESCE(open, ff_close) AS open, + COALESCE(high, ff_close) AS high, + COALESCE(low, ff_close) AS low, + COALESCE(close, ff_close) AS close, + COALESCE(oracle_close, ff_oracle) AS oracle_close, + COALESCE(ticks, 0) AS ticks + FROM ff ORDER BY bucket DESC LIMIT p_limit; $$;