Files
foxhunt/migrations/048_broker_integration.sql
jgrusewski 86f7f1fa76 fix: comprehensive audit — real brokers, deployment fixes, production safety
Codebase audit identified 23 findings across 4 dimensions (production safety,
code health, deployment readiness, test quality). This commit fixes all of them.

Broker execution layer (was entirely stubbed):
- Real IBKR TWS client via ibapi crate (950+ lines, feature-gated)
- ICMarkets ctrader-openapi now always-on (removed feature flag)
- Real broker routing with health monitoring and exponential backoff reconnect
- Validated against live IB Gateway Docker (6/6 connectivity tests pass)

Deployment blockers:
- Fixed 6 broken Dockerfiles (removed COPY foxhunt-deploy)
- Created foxhunt K8s namespace, secret templates, migration job
- Added liveness probes to all 7 K8s services
- IB Gateway manifest (ghcr.io/gnzsnz/ib-gateway:stable)
- IBKR credentials in Scaleway Secret Manager via Terragrunt
- Fixed port collisions and mismatches across services

Production safety (9 critical + 6 high/medium fixes):
- Asset-class-specific VaR volatility (not flat 2%)
- Real parametric VaR with z-score 95th percentile
- Kyle's lambda regression (100-bar rolling window)
- Per-feature running statistics from historical data
- VWAP-based slippage reference, regime duration tracking
- Real Databento JSON parsing for OHLCV/Trade/Quote

Code health:
- Removed #![allow(dead_code)] from ml, data, config
- Fixed log:: → tracing:: in 4 production files
- Removed dead workspace deps (ratatui, crossterm)

Verified: cargo check --workspace (0 errors), trading_engine 330 tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 00:32:10 +01:00

157 lines
7.9 KiB
PL/PgSQL

-- 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;