-- Migration 011: Create Market Data Tables -- This migration creates all the missing market data tables required for SQLx compilation -- Tables: prices, order_book_levels, technical_indicators, market_ticks, candles -- Enable required extensions if not already enabled CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "btree_gin"; -- Prices table - stores bid/ask/last prices and OHLCV data CREATE TABLE IF NOT EXISTS prices ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), symbol VARCHAR(32) NOT NULL, timestamp TIMESTAMP WITH TIME ZONE NOT NULL, bid BIGINT, -- Bid price in fixed-point cents ask BIGINT, -- Ask price in fixed-point cents last BIGINT, -- Last trade price in fixed-point cents volume BIGINT, -- Volume traded open BIGINT, -- Opening price in fixed-point cents high BIGINT, -- High price in fixed-point cents low BIGINT, -- Low price in fixed-point cents close BIGINT, -- Closing price in fixed-point cents created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), UNIQUE(symbol, timestamp) ); -- Order book levels table - stores order book depth data CREATE TABLE IF NOT EXISTS order_book_levels ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), symbol VARCHAR(32) NOT NULL, timestamp TIMESTAMP WITH TIME ZONE NOT NULL, side VARCHAR(10) NOT NULL CHECK (side IN ('bid', 'ask')), price BIGINT NOT NULL, -- Price level in fixed-point cents quantity BIGINT NOT NULL, -- Quantity at this level level INTEGER NOT NULL, -- Level in the book (0 = best bid/ask) created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), UNIQUE(symbol, timestamp, side, level) ); -- Technical indicators table - stores computed technical indicators CREATE TABLE IF NOT EXISTS technical_indicators ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), symbol VARCHAR(32) NOT NULL, indicator_name VARCHAR(64) NOT NULL, indicator_type VARCHAR(32) NOT NULL, timestamp TIMESTAMP WITH TIME ZONE NOT NULL, value DECIMAL(20, 8) NOT NULL, parameters JSONB, -- Indicator-specific parameters metadata JSONB, -- Additional metadata created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), UNIQUE(symbol, indicator_name, timestamp) ); -- Market ticks table - stores raw market tick data CREATE TABLE IF NOT EXISTS market_ticks ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), symbol VARCHAR(32) NOT NULL, timestamp TIMESTAMP WITH TIME ZONE NOT NULL, price BIGINT NOT NULL, -- Tick price in fixed-point cents quantity BIGINT NOT NULL, -- Tick quantity side VARCHAR(10) CHECK (side IN ('buy', 'sell')), tick_type VARCHAR(20) NOT NULL, -- trade, bid, ask, etc. exchange VARCHAR(32), -- Exchange identifier sequence_number BIGINT, -- Exchange sequence number conditions JSONB, -- Trade conditions/flags created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); -- Candles table - stores OHLCV candlestick data CREATE TABLE IF NOT EXISTS candles ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), symbol VARCHAR(32) NOT NULL, period VARCHAR(10) NOT NULL, -- 1m, 5m, 15m, 1h, 1d, etc. timestamp TIMESTAMP WITH TIME ZONE NOT NULL, -- Start of the period open BIGINT NOT NULL, -- Opening price in fixed-point cents high BIGINT NOT NULL, -- High price in fixed-point cents low BIGINT NOT NULL, -- Low price in fixed-point cents close BIGINT NOT NULL, -- Closing price in fixed-point cents volume BIGINT NOT NULL DEFAULT 0, -- Total volume trade_count INTEGER DEFAULT 0, -- Number of trades in period vwap BIGINT, -- Volume-weighted average price created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), UNIQUE(symbol, period, timestamp) ); -- Create indexes for optimal query performance -- Prices table indexes CREATE INDEX IF NOT EXISTS idx_prices_symbol_timestamp ON prices(symbol, timestamp DESC); CREATE INDEX IF NOT EXISTS idx_prices_timestamp ON prices(timestamp DESC); CREATE INDEX IF NOT EXISTS idx_prices_symbol ON prices(symbol); -- Order book levels indexes CREATE INDEX IF NOT EXISTS idx_order_book_levels_symbol_timestamp ON order_book_levels(symbol, timestamp DESC); CREATE INDEX IF NOT EXISTS idx_order_book_levels_symbol_side_timestamp ON order_book_levels(symbol, side, timestamp DESC); CREATE INDEX IF NOT EXISTS idx_order_book_levels_timestamp ON order_book_levels(timestamp DESC); -- Technical indicators indexes CREATE INDEX IF NOT EXISTS idx_technical_indicators_symbol_name_timestamp ON technical_indicators(symbol, indicator_name, timestamp DESC); CREATE INDEX IF NOT EXISTS idx_technical_indicators_timestamp ON technical_indicators(timestamp DESC); -- Market ticks indexes CREATE INDEX IF NOT EXISTS idx_market_ticks_symbol_timestamp ON market_ticks(symbol, timestamp DESC); CREATE INDEX IF NOT EXISTS idx_market_ticks_timestamp ON market_ticks(timestamp DESC); CREATE INDEX IF NOT EXISTS idx_market_ticks_sequence ON market_ticks(exchange, sequence_number); -- Candles indexes CREATE INDEX IF NOT EXISTS idx_candles_symbol_period_timestamp ON candles(symbol, period, timestamp DESC); CREATE INDEX IF NOT EXISTS idx_candles_timestamp ON candles(timestamp DESC); -- Partitioning for large tables (commented out for initial setup, can be enabled later) -- This would be useful for production deployments with high data volumes /* -- Example partitioning setup for prices table (by month) -- CREATE TABLE prices_partitioned (LIKE prices INCLUDING ALL) PARTITION BY RANGE (timestamp); -- CREATE TABLE prices_y2025m01 PARTITION OF prices_partitioned FOR VALUES FROM ('2025-01-01') TO ('2025-02-01'); -- CREATE TABLE prices_y2025m02 PARTITION OF prices_partitioned FOR VALUES FROM ('2025-02-01') TO ('2025-03-01'); -- ... continue for each month */ -- Add triggers for updating timestamps CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ language 'plpgsql'; -- Apply update trigger to candles table CREATE TRIGGER update_candles_updated_at BEFORE UPDATE ON candles FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); -- Add comments for documentation COMMENT ON TABLE prices IS 'Market price data with bid/ask/last prices and OHLCV data'; COMMENT ON TABLE order_book_levels IS 'Order book depth data with price levels and quantities'; COMMENT ON TABLE technical_indicators IS 'Computed technical indicators (RSI, MACD, etc.)'; COMMENT ON TABLE market_ticks IS 'Raw market tick data from exchanges'; COMMENT ON TABLE candles IS 'OHLCV candlestick data for various time periods'; -- Grant permissions (assuming the trading service user exists from previous migrations) DO $$ BEGIN IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'trading_service') THEN GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO trading_service; GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO trading_service; END IF; END $$;