-- Migration 046: Broker Integration (AMP Futures / CQG FIX API)
-- Description: Database schema for FIX order routing, execution tracking, and session management
-- Date: 2025-11-09

BEGIN;

-- ============================================================================
-- broker_orders: Audit trail for all broker orders
-- ============================================================================

CREATE TABLE IF NOT EXISTS broker_orders (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    client_order_id VARCHAR(64) NOT NULL UNIQUE,  -- Our ClOrdID (Tag 11)
    broker_order_id VARCHAR(64),                  -- Broker OrderID (Tag 37, nullable until ACK)
    account_id VARCHAR(64) NOT NULL,              -- AMP account identifier
    symbol VARCHAR(32) NOT NULL,                  -- ES, NQ, etc.
    side VARCHAR(4) NOT NULL,                     -- BUY, SELL
    order_type VARCHAR(16) NOT NULL,              -- MARKET, LIMIT, STOP, STOP_LIMIT
    quantity NUMERIC(18, 8) NOT NULL,             -- Contracts
    price NUMERIC(18, 8),                         -- NULL for market orders
    stop_price NUMERIC(18, 8),                    -- For stop orders
    time_in_force VARCHAR(8) NOT NULL DEFAULT 'DAY', -- DAY, IOC, GTC
    status VARCHAR(32) NOT NULL,                  -- PENDING_SUBMIT, SUBMITTED, FILLED, etc.
    filled_quantity NUMERIC(18, 8) DEFAULT 0,     -- Cumulative filled quantity
    avg_fill_price NUMERIC(18, 8),                -- Average fill price
    metadata JSONB,                               -- Strategy, model_name, etc.
    submitted_at TIMESTAMPTZ,                     -- When submitted to broker
    filled_at TIMESTAMPTZ,                        -- When fully filled
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- Indexes for broker_orders
CREATE INDEX idx_broker_orders_client_order_id ON broker_orders(client_order_id);
CREATE INDEX idx_broker_orders_broker_order_id ON broker_orders(broker_order_id) WHERE broker_order_id IS NOT NULL;
CREATE INDEX idx_broker_orders_account ON broker_orders(account_id);
CREATE INDEX idx_broker_orders_status ON broker_orders(status);
CREATE INDEX idx_broker_orders_symbol ON broker_orders(symbol);
CREATE INDEX idx_broker_orders_created_at ON broker_orders(created_at DESC);

-- ============================================================================
-- broker_executions: Execution reports from broker
-- ============================================================================

CREATE TABLE IF NOT EXISTS broker_executions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    execution_id VARCHAR(64) NOT NULL UNIQUE,     -- ExecID (Tag 17)
    broker_order_id VARCHAR(64) NOT NULL,         -- OrderID (Tag 37)
    client_order_id VARCHAR(64) NOT NULL,         -- ClOrdID (Tag 11)
    symbol VARCHAR(32) NOT NULL,
    side VARCHAR(4) NOT NULL,                     -- BUY, SELL
    exec_type VARCHAR(16) NOT NULL,               -- NEW, TRADE, CANCELED, REJECTED
    order_status VARCHAR(32) NOT NULL,            -- Order status after this execution
    last_qty NUMERIC(18, 8),                      -- Quantity filled in this report (Tag 32)
    last_price NUMERIC(18, 8),                    -- Fill price (Tag 31)
    cum_qty NUMERIC(18, 8),                       -- Total filled quantity (Tag 14)
    avg_price NUMERIC(18, 8),                     -- Average fill price (Tag 6)
    commission NUMERIC(18, 8),                    -- Commission charged
    transact_time TIMESTAMPTZ NOT NULL,           -- Exchange execution time
    text TEXT,                                    -- Reject reason or notes
    raw_fix_message TEXT,                         -- Full FIX message for audit
    received_at TIMESTAMPTZ DEFAULT NOW(),

    CONSTRAINT fk_broker_executions_order
        FOREIGN KEY (client_order_id)
        REFERENCES broker_orders(client_order_id)
        ON DELETE CASCADE
);

-- Indexes for broker_executions
CREATE INDEX idx_broker_executions_execution_id ON broker_executions(execution_id);
CREATE INDEX idx_broker_executions_broker_order_id ON broker_executions(broker_order_id);
CREATE INDEX idx_broker_executions_client_order_id ON broker_executions(client_order_id);
CREATE INDEX idx_broker_executions_symbol ON broker_executions(symbol);
CREATE INDEX idx_broker_executions_transact_time ON broker_executions(transact_time DESC);
CREATE INDEX idx_broker_executions_exec_type ON broker_executions(exec_type);

-- ============================================================================
-- fix_sessions: FIX session state for recovery
-- ============================================================================

CREATE TABLE IF NOT EXISTS fix_sessions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    session_id VARCHAR(128) NOT NULL UNIQUE,      -- "FOXHUNT_CLIENT-CQG"
    sender_comp_id VARCHAR(64) NOT NULL,          -- Tag 49 (SenderCompID)
    target_comp_id VARCHAR(64) NOT NULL,          -- Tag 56 (TargetCompID)
    sender_seq_num BIGINT NOT NULL DEFAULT 1,     -- Our outgoing sequence number
    target_seq_num BIGINT NOT NULL DEFAULT 1,     -- Expected incoming sequence number
    session_state VARCHAR(32) NOT NULL,           -- DISCONNECTED, CONNECTED, ACTIVE, etc.
    last_heartbeat_sent TIMESTAMPTZ,
    last_heartbeat_received TIMESTAMPTZ,
    connected_at TIMESTAMPTZ,
    disconnected_at TIMESTAMPTZ,
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- Indexes for fix_sessions
CREATE INDEX idx_fix_sessions_session_id ON fix_sessions(session_id);
CREATE INDEX idx_fix_sessions_state ON fix_sessions(session_state);

-- ============================================================================
-- broker_account_state: Real-time account balances and positions
-- ============================================================================

CREATE TABLE IF NOT EXISTS broker_account_state (
    account_id VARCHAR(64) PRIMARY KEY,
    cash_balance NUMERIC(18, 2) NOT NULL,
    equity NUMERIC(18, 2) NOT NULL,
    margin_used NUMERIC(18, 2) NOT NULL,
    margin_available NUMERIC(18, 2) NOT NULL,
    buying_power NUMERIC(18, 2) NOT NULL,
    unrealized_pnl NUMERIC(18, 2) DEFAULT 0,
    realized_pnl NUMERIC(18, 2) DEFAULT 0,
    last_updated TIMESTAMPTZ DEFAULT NOW()
);

-- Index for broker_account_state
CREATE INDEX idx_broker_account_state_last_updated ON broker_account_state(last_updated DESC);

-- ============================================================================
-- broker_positions: Real-time position tracking per symbol
-- ============================================================================

CREATE TABLE IF NOT EXISTS broker_positions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    account_id VARCHAR(64) NOT NULL,
    symbol VARCHAR(32) NOT NULL,
    quantity NUMERIC(18, 8) NOT NULL DEFAULT 0,   -- Positive = long, negative = short
    average_price NUMERIC(18, 8),
    market_value NUMERIC(18, 2),
    unrealized_pnl NUMERIC(18, 2) DEFAULT 0,
    last_updated TIMESTAMPTZ DEFAULT NOW(),

    CONSTRAINT uq_broker_positions_account_symbol UNIQUE (account_id, symbol)
);

-- Indexes for broker_positions
CREATE INDEX idx_broker_positions_account ON broker_positions(account_id);
CREATE INDEX idx_broker_positions_symbol ON broker_positions(symbol);
CREATE INDEX idx_broker_positions_last_updated ON broker_positions(last_updated DESC);

-- ============================================================================
-- Grant permissions
-- ============================================================================

GRANT SELECT, INSERT, UPDATE, DELETE ON broker_orders TO foxhunt;
GRANT SELECT, INSERT ON broker_executions TO foxhunt;
GRANT SELECT, INSERT, UPDATE ON fix_sessions TO foxhunt;
GRANT SELECT, INSERT, UPDATE ON broker_account_state TO foxhunt;
GRANT SELECT, INSERT, UPDATE, DELETE ON broker_positions TO foxhunt;

-- ============================================================================
-- Commit migration
-- ============================================================================

COMMIT;
