chore(snapshot): sync workspace state
This commit is contained in:
@@ -111,8 +111,52 @@ ALTER TABLE api_tokens ADD COLUMN IF NOT EXISTS scopes TEXT[] NOT NULL DEFAULT A
|
||||
CREATE INDEX IF NOT EXISTS api_tokens_revoked_at_idx
|
||||
ON api_tokens (revoked_at);
|
||||
|
||||
-- Bot control-plane (desired state) + executor telemetry (state/events).
|
||||
--
|
||||
-- MVP intent:
|
||||
-- - `bot_config`: desired state (mode/market/limits/kill switch)
|
||||
-- - `bot_state`: heartbeat + last error/action
|
||||
-- - `bot_events`: append-only audit log
|
||||
CREATE TABLE IF NOT EXISTS public.bot_config (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
market_name TEXT NOT NULL,
|
||||
market_type TEXT NOT NULL DEFAULT 'perp',
|
||||
mode TEXT NOT NULL DEFAULT 'off',
|
||||
kill_switch BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
params JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS bot_config_updated_at_desc_idx
|
||||
ON public.bot_config (updated_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.bot_state (
|
||||
bot_id UUID PRIMARY KEY REFERENCES public.bot_config(id) ON DELETE CASCADE,
|
||||
last_heartbeat_at TIMESTAMPTZ,
|
||||
last_action_at TIMESTAMPTZ,
|
||||
last_error TEXT,
|
||||
state JSONB,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS bot_state_updated_at_desc_idx
|
||||
ON public.bot_state (updated_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.bot_events (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
bot_id UUID NOT NULL REFERENCES public.bot_config(id) ON DELETE CASCADE,
|
||||
ts TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
type TEXT NOT NULL,
|
||||
payload JSONB
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS bot_events_bot_ts_desc_idx
|
||||
ON public.bot_events (bot_id, ts DESC);
|
||||
|
||||
-- Compute OHLC candles from `drift_ticks` for a symbol and bucket size.
|
||||
-- Exposed via Hasura (track function) and used by trade-api to compute indicators server-side.
|
||||
-- Exposed via Hasura (track function) for server-side candle aggregation and indicator reads.
|
||||
-- Hasura tracks functions only if they return SETOF a table/view type.
|
||||
-- This table is used purely as the return type for candle functions.
|
||||
CREATE TABLE IF NOT EXISTS public.drift_candles (
|
||||
@@ -838,41 +882,8 @@ CREATE TABLE IF NOT EXISTS public.dlob_orderbook_l2_latest (
|
||||
PRIMARY KEY (source, market_name, is_indicative)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.dlob_orderbook_l3_latest (
|
||||
source TEXT NOT NULL,
|
||||
market_name TEXT NOT NULL,
|
||||
market_type TEXT NOT NULL,
|
||||
market_index INTEGER,
|
||||
is_indicative BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ts BIGINT,
|
||||
slot BIGINT,
|
||||
oracle_data JSONB,
|
||||
bids JSONB,
|
||||
asks JSONB,
|
||||
payload JSONB NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (source, market_name, is_indicative)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.dlob_best_makers_latest (
|
||||
source TEXT NOT NULL,
|
||||
market_name TEXT NOT NULL,
|
||||
market_type TEXT NOT NULL,
|
||||
market_index INTEGER,
|
||||
slot BIGINT,
|
||||
bids JSONB,
|
||||
asks JSONB,
|
||||
payload JSONB NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (source, market_name)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_orderbook_l2_latest_updated_at_idx
|
||||
ON public.dlob_orderbook_l2_latest (updated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS dlob_orderbook_l3_latest_updated_at_idx
|
||||
ON public.dlob_orderbook_l3_latest (updated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS dlob_best_makers_latest_updated_at_idx
|
||||
ON public.dlob_best_makers_latest (updated_at DESC);
|
||||
|
||||
CREATE OR REPLACE VIEW public.dlob_l2_latest_projection AS
|
||||
SELECT
|
||||
@@ -905,34 +916,6 @@ SELECT
|
||||
FROM public.dlob_orderbook_l2_latest
|
||||
WHERE is_indicative = FALSE;
|
||||
|
||||
CREATE OR REPLACE VIEW public.dlob_l3_latest_projection AS
|
||||
SELECT
|
||||
source,
|
||||
market_name,
|
||||
market_type,
|
||||
market_index,
|
||||
ts,
|
||||
slot,
|
||||
bids,
|
||||
asks,
|
||||
payload AS raw,
|
||||
updated_at
|
||||
FROM public.dlob_orderbook_l3_latest
|
||||
WHERE is_indicative = FALSE;
|
||||
|
||||
CREATE OR REPLACE VIEW public.dlob_best_makers_latest_projection AS
|
||||
SELECT
|
||||
source,
|
||||
market_name,
|
||||
market_type,
|
||||
market_index,
|
||||
slot,
|
||||
bids,
|
||||
asks,
|
||||
payload AS raw,
|
||||
updated_at
|
||||
FROM public.dlob_best_makers_latest;
|
||||
|
||||
CREATE OR REPLACE VIEW public.dlob_stats_latest_projection AS
|
||||
WITH base AS (
|
||||
SELECT
|
||||
@@ -1057,3 +1040,286 @@ SELECT
|
||||
FROM base b
|
||||
LEFT JOIN bid_levels bids USING (source, market_name)
|
||||
LEFT JOIN ask_levels asks USING (source, market_name);
|
||||
|
||||
-- Retired legacy DLOB read-side pipeline artifacts. Keep this cleanup in initdb so
|
||||
-- fresh volumes and reused volumes both converge on the current Redis -> derived tables workflow.
|
||||
DROP VIEW IF EXISTS public.dlob_l2_latest_projection;
|
||||
DROP VIEW IF EXISTS public.dlob_stats_latest_projection;
|
||||
DROP TABLE IF EXISTS public.dlob_l2_latest;
|
||||
DROP TABLE IF EXISTS public.dlob_stats_latest;
|
||||
DROP TABLE IF EXISTS public.dlob_depth_bps_latest;
|
||||
DROP TABLE IF EXISTS public.dlob_slippage_latest;
|
||||
DROP TABLE IF EXISTS public.dlob_slippage_latest_v2;
|
||||
DROP TABLE IF EXISTS public.dlob_stats_ts;
|
||||
DROP TABLE IF EXISTS public.dlob_depth_bps_ts;
|
||||
DROP TABLE IF EXISTS public.dlob_slippage_ts;
|
||||
DROP TABLE IF EXISTS public.dlob_slippage_ts_v2;
|
||||
DROP TABLE IF EXISTS public.dlob_orderbook_l2_latest;
|
||||
|
||||
-- Canonical raw DLOB hot snapshots written from Redis to PostgreSQL.
|
||||
CREATE TABLE IF NOT EXISTS public.dlob_hot_snapshot_latest (
|
||||
source TEXT NOT NULL,
|
||||
redis_key TEXT NOT NULL,
|
||||
snapshot_kind TEXT NOT NULL CHECK (snapshot_kind IN ('orderbook_l2', 'orderbook_l3', 'best_makers')),
|
||||
market_type TEXT NOT NULL,
|
||||
market_index INTEGER NOT NULL,
|
||||
market_name TEXT NOT NULL,
|
||||
is_indicative BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ts_ms BIGINT NOT NULL,
|
||||
slot BIGINT,
|
||||
market_slot BIGINT,
|
||||
payload_hash TEXT NOT NULL,
|
||||
mark_price_raw TEXT,
|
||||
oracle_price_raw TEXT,
|
||||
best_bid_price_raw TEXT,
|
||||
best_ask_price_raw TEXT,
|
||||
spread_pct_raw TEXT,
|
||||
spread_quote_raw TEXT,
|
||||
oracle_data JSONB,
|
||||
bids JSONB,
|
||||
asks JSONB,
|
||||
payload JSONB NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (source, market_type, market_index, snapshot_kind, is_indicative)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_hot_snapshot_latest_updated_at_idx
|
||||
ON public.dlob_hot_snapshot_latest (updated_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_hot_snapshot_latest_source_market_idx
|
||||
ON public.dlob_hot_snapshot_latest (source, market_type, market_index, updated_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.dlob_hot_snapshot_ts (
|
||||
event_ts TIMESTAMPTZ NOT NULL,
|
||||
id BIGSERIAL NOT NULL,
|
||||
source TEXT NOT NULL,
|
||||
redis_key TEXT NOT NULL,
|
||||
snapshot_kind TEXT NOT NULL CHECK (snapshot_kind IN ('orderbook_l2', 'orderbook_l3', 'best_makers')),
|
||||
market_type TEXT NOT NULL,
|
||||
market_index INTEGER NOT NULL,
|
||||
market_name TEXT NOT NULL,
|
||||
is_indicative BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ts_ms BIGINT NOT NULL,
|
||||
slot BIGINT,
|
||||
market_slot BIGINT,
|
||||
payload_hash TEXT NOT NULL,
|
||||
mark_price_raw TEXT,
|
||||
oracle_price_raw TEXT,
|
||||
best_bid_price_raw TEXT,
|
||||
best_ask_price_raw TEXT,
|
||||
spread_pct_raw TEXT,
|
||||
spread_quote_raw TEXT,
|
||||
oracle_data JSONB,
|
||||
bids JSONB,
|
||||
asks JSONB,
|
||||
payload JSONB NOT NULL,
|
||||
inserted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (event_ts, id)
|
||||
);
|
||||
|
||||
SELECT create_hypertable('dlob_hot_snapshot_ts', 'event_ts', if_not_exists => TRUE, migrate_data => TRUE);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS dlob_hot_snapshot_ts_dedupe_idx
|
||||
ON public.dlob_hot_snapshot_ts (event_ts, source, redis_key, payload_hash);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_hot_snapshot_ts_market_ts_desc_idx
|
||||
ON public.dlob_hot_snapshot_ts (market_type, market_index, event_ts DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_hot_snapshot_ts_source_market_ts_desc_idx
|
||||
ON public.dlob_hot_snapshot_ts (source, market_type, market_index, event_ts DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.dlob_hot_derived_latest (
|
||||
source TEXT NOT NULL,
|
||||
market_type TEXT NOT NULL,
|
||||
market_index INTEGER NOT NULL,
|
||||
market_name TEXT NOT NULL,
|
||||
is_indicative BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ts_ms BIGINT NOT NULL,
|
||||
slot BIGINT,
|
||||
market_slot BIGINT,
|
||||
mark_price NUMERIC,
|
||||
oracle_price NUMERIC,
|
||||
best_bid_price NUMERIC,
|
||||
best_ask_price NUMERIC,
|
||||
mid_price NUMERIC,
|
||||
spread_quote NUMERIC,
|
||||
spread_bps NUMERIC,
|
||||
depth_levels INTEGER NOT NULL,
|
||||
bid_levels INTEGER NOT NULL,
|
||||
ask_levels INTEGER NOT NULL,
|
||||
top_bid_size NUMERIC,
|
||||
top_ask_size NUMERIC,
|
||||
top_bid_notional NUMERIC,
|
||||
top_ask_notional NUMERIC,
|
||||
depth_bid_base NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_ask_base NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_bid_quote NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_ask_quote NUMERIC NOT NULL DEFAULT 0,
|
||||
imbalance NUMERIC,
|
||||
bids_norm JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
asks_norm JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
raw_payload_hash TEXT NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (source, market_type, market_index, is_indicative)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_hot_derived_latest_updated_at_idx
|
||||
ON public.dlob_hot_derived_latest (updated_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_hot_derived_latest_source_market_idx
|
||||
ON public.dlob_hot_derived_latest (source, market_type, market_index, updated_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.dlob_hot_derived_ts (
|
||||
event_ts TIMESTAMPTZ NOT NULL,
|
||||
id BIGSERIAL NOT NULL,
|
||||
source TEXT NOT NULL,
|
||||
market_type TEXT NOT NULL,
|
||||
market_index INTEGER NOT NULL,
|
||||
market_name TEXT NOT NULL,
|
||||
is_indicative BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ts_ms BIGINT NOT NULL,
|
||||
slot BIGINT,
|
||||
market_slot BIGINT,
|
||||
mark_price NUMERIC,
|
||||
oracle_price NUMERIC,
|
||||
best_bid_price NUMERIC,
|
||||
best_ask_price NUMERIC,
|
||||
mid_price NUMERIC,
|
||||
spread_quote NUMERIC,
|
||||
spread_bps NUMERIC,
|
||||
depth_levels INTEGER NOT NULL,
|
||||
bid_levels INTEGER NOT NULL,
|
||||
ask_levels INTEGER NOT NULL,
|
||||
top_bid_size NUMERIC,
|
||||
top_ask_size NUMERIC,
|
||||
top_bid_notional NUMERIC,
|
||||
top_ask_notional NUMERIC,
|
||||
depth_bid_base NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_ask_base NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_bid_quote NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_ask_quote NUMERIC NOT NULL DEFAULT 0,
|
||||
imbalance NUMERIC,
|
||||
bids_norm JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
asks_norm JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
raw_payload_hash TEXT NOT NULL,
|
||||
inserted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (event_ts, id)
|
||||
);
|
||||
|
||||
SELECT create_hypertable('dlob_hot_derived_ts', 'event_ts', if_not_exists => TRUE, migrate_data => TRUE);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS dlob_hot_derived_ts_dedupe_idx
|
||||
ON public.dlob_hot_derived_ts (event_ts, source, market_type, market_index, is_indicative, raw_payload_hash);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_hot_derived_ts_market_ts_desc_idx
|
||||
ON public.dlob_hot_derived_ts (market_type, market_index, event_ts DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_hot_derived_ts_source_market_ts_desc_idx
|
||||
ON public.dlob_hot_derived_ts (source, market_type, market_index, event_ts DESC);
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
PERFORM add_retention_policy('dlob_hot_snapshot_ts', INTERVAL '30 days');
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
PERFORM add_retention_policy('dlob_hot_derived_ts', INTERVAL '180 days');
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.dlob_all_derived_latest (
|
||||
source TEXT NOT NULL,
|
||||
market_type TEXT NOT NULL,
|
||||
market_index INTEGER NOT NULL,
|
||||
market_name TEXT NOT NULL,
|
||||
is_indicative BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ts_ms BIGINT NOT NULL,
|
||||
slot BIGINT,
|
||||
market_slot BIGINT,
|
||||
mark_price NUMERIC,
|
||||
oracle_price NUMERIC,
|
||||
best_bid_price NUMERIC,
|
||||
best_ask_price NUMERIC,
|
||||
mid_price NUMERIC,
|
||||
spread_quote NUMERIC,
|
||||
spread_bps NUMERIC,
|
||||
depth_levels INTEGER NOT NULL,
|
||||
bid_levels INTEGER NOT NULL,
|
||||
ask_levels INTEGER NOT NULL,
|
||||
top_bid_size NUMERIC,
|
||||
top_ask_size NUMERIC,
|
||||
top_bid_notional NUMERIC,
|
||||
top_ask_notional NUMERIC,
|
||||
depth_bid_base NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_ask_base NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_bid_quote NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_ask_quote NUMERIC NOT NULL DEFAULT 0,
|
||||
imbalance NUMERIC,
|
||||
bids_norm JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
asks_norm JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
raw_payload_hash TEXT NOT NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (source, market_type, market_index, is_indicative)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_all_derived_latest_updated_at_idx
|
||||
ON public.dlob_all_derived_latest (updated_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_all_derived_latest_source_market_idx
|
||||
ON public.dlob_all_derived_latest (source, market_type, market_index, updated_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.dlob_all_derived_ts (
|
||||
event_ts TIMESTAMPTZ NOT NULL,
|
||||
id BIGSERIAL NOT NULL,
|
||||
source TEXT NOT NULL,
|
||||
market_type TEXT NOT NULL,
|
||||
market_index INTEGER NOT NULL,
|
||||
market_name TEXT NOT NULL,
|
||||
is_indicative BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
ts_ms BIGINT NOT NULL,
|
||||
slot BIGINT,
|
||||
market_slot BIGINT,
|
||||
mark_price NUMERIC,
|
||||
oracle_price NUMERIC,
|
||||
best_bid_price NUMERIC,
|
||||
best_ask_price NUMERIC,
|
||||
mid_price NUMERIC,
|
||||
spread_quote NUMERIC,
|
||||
spread_bps NUMERIC,
|
||||
depth_levels INTEGER NOT NULL,
|
||||
bid_levels INTEGER NOT NULL,
|
||||
ask_levels INTEGER NOT NULL,
|
||||
top_bid_size NUMERIC,
|
||||
top_ask_size NUMERIC,
|
||||
top_bid_notional NUMERIC,
|
||||
top_ask_notional NUMERIC,
|
||||
depth_bid_base NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_ask_base NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_bid_quote NUMERIC NOT NULL DEFAULT 0,
|
||||
depth_ask_quote NUMERIC NOT NULL DEFAULT 0,
|
||||
imbalance NUMERIC,
|
||||
bids_norm JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
asks_norm JSONB NOT NULL DEFAULT '[]'::jsonb,
|
||||
raw_payload_hash TEXT NOT NULL,
|
||||
inserted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (event_ts, id)
|
||||
);
|
||||
|
||||
SELECT create_hypertable('dlob_all_derived_ts', 'event_ts', if_not_exists => TRUE, migrate_data => TRUE);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS dlob_all_derived_ts_dedupe_idx
|
||||
ON public.dlob_all_derived_ts (event_ts, source, market_type, market_index, is_indicative, raw_payload_hash);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_all_derived_ts_market_ts_desc_idx
|
||||
ON public.dlob_all_derived_ts (market_type, market_index, event_ts DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS dlob_all_derived_ts_source_market_ts_desc_idx
|
||||
ON public.dlob_all_derived_ts (source, market_type, market_index, event_ts DESC);
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
PERFORM add_retention_policy('dlob_all_derived_ts', INTERVAL '30 days');
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
Reference in New Issue
Block a user