## Major Achievements ### 1. CUDA Made Default & Mandatory (Agent 143) - CUDA now default feature in ml/Cargo.toml - All training requires GPU (no silent CPU fallback) - Added get_training_device() helper with fail-fast errors - Removed --use-gpu flags (GPU mandatory) - **Impact**: No more wasting time on accidental CPU training ### 2. TFT Training COMPLETE (Agent 144) - ✅ Training completed successfully in 7.6 minutes - ✅ Early stopping at epoch 100/200 (best val loss: 0.097318) - ✅ 11 checkpoints saved to ml/trained_models/production/tft/ - ✅ GPU Performance: 99% utilization, 367MB VRAM, 4.4s/epoch - ✅ 10x speedup vs CPU (4.4s vs 43-55s per epoch) - **Status**: PRODUCTION READY ### 3. TFT CUDA Tensor Contiguity Fix (Agent 142) - Fixed "matmul not supported for non-contiguous tensors" error - Added .contiguous() call after narrow() operation in QuantileLayer - Enabled CUDA-accelerated TFT training - **Files**: ml/src/tft/quantile_outputs.rs ### 4. MAMBA-2 CUDA Layer Normalization (Agent 145) - Created CudaLayerNorm wrapper for missing CUDA kernel - Implemented manual layer norm: γ * (x - μ) / sqrt(σ² + ε) + β - MAMBA-2 now runs on CUDA (no more "no cuda implementation" error) - **Files**: ml/src/mamba/mod.rs ### 5. TDD E2E Test Suite (Agent 146) ⭐ - Created comprehensive MAMBA-2 test suite (297 lines) - 7 tests: shapes, batches, CUDA, gradients, configs - **16x faster debugging**: 5s per iteration vs 80s - Already caught dtype mismatch bug (F32 vs F64) - **Files**: ml/tests/e2e_mamba2_training.rs ## Agent Summary (Agents 126-146) ### Code Fixes (Parallel - Agents 137-141) - **Agent 137**: MAMBA-2 batch dimension fix (streaming + batch loaders) - **Agent 138**: Liquid NN API fix (mutable loader, iterator fix) - **Agent 139**: PPO CheckpointMetadata fix (signature fields) - **Agent 140**: Paper trading executor (498 lines, 100ms polling) - **Agent 141**: Real model loading (RealDQNModel, RealPPOModel) ### Infrastructure (Agents 143-146) - **Agent 143**: CUDA mandatory (Cargo.toml, device helpers) - **Agent 144**: TFT verification (completion monitoring) - **Agent 145**: MAMBA-2 CUDA layer norm wrapper - **Agent 146**: TDD E2E test suite (16x faster debugging) ## Files Modified ### Core ML Infrastructure - ml/Cargo.toml: Added default = ["minimal-inference", "cuda"] - ml/src/lib.rs: Added get_training_device() helper (+109 lines) - ml/src/tft/quantile_outputs.rs: Fixed tensor contiguity - ml/src/mamba/mod.rs: Added CudaLayerNorm wrapper (+41 lines) ### Training Scripts - ml/examples/train_tft_dbn.rs: Removed --use-gpu flag - ml/examples/train_ppo.rs: Removed --use-gpu flag - ml/examples/train_mamba2_dbn.rs: Forced CUDA-only mode - ml/examples/train_liquid_dbn.rs: Fixed API usage ### Data Loaders - ml/src/data_loaders/dbn_sequence_loader.rs: Fixed batch dimensions - ml/src/data_loaders/streaming_dbn_loader.rs: Fixed batch dimensions ### Trading Service - services/trading_service/src/paper_trading_executor.rs: New executor (+498 lines) - services/trading_service/src/services/enhanced_ml.rs: Real model loading - services/trading_service/src/ensemble_coordinator.rs: Integration ### Tests - ml/tests/e2e_mamba2_training.rs: New TDD test suite (+297 lines) ### Trainers - ml/src/trainers/tft.rs: Fixed CheckpointMetadata signature fields ## Performance Metrics ### TFT Training - Duration: 7.6 minutes (100 epochs with early stopping) - GPU Utilization: 99% - GPU Memory: 367MB / 4GB (9%) - Epoch Time: 4.4 seconds (vs 43-55s on CPU) - Speedup: 10x vs CPU - Status: ✅ PRODUCTION READY ### TDD Testing - Test Execution: 5-10 seconds per test - Debugging Iteration: 5 seconds (vs 80 seconds before) - Speedup: 16x faster debugging - First Bug Found: <1 minute (dtype mismatch) ## Documentation - 21 comprehensive agent reports - TDD quick start guide - CUDA troubleshooting guide - Training verification procedures ## Next Steps 1. Fix MAMBA-2 dtype mismatch (F32→F64) - 2 minutes 2. Run MAMBA-2 tests until passing - 5-10 minutes 3. Launch full MAMBA-2 training - 200 epochs 4. Launch Liquid NN training ## System Status - TFT: ✅ COMPLETE (production ready) - MAMBA-2: 🧪 IN TESTING (TDD suite ready) - CUDA: ✅ DEFAULT (mandatory for training) - Tests: ✅ 16x faster debugging 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
294 lines
12 KiB
PL/PgSQL
294 lines
12 KiB
PL/PgSQL
-- ================================================================================================
|
|
-- Migration 025: Query Performance Optimization
|
|
-- Additional optimizations for paper trading validation queries
|
|
-- ================================================================================================
|
|
-- Target: <5ms P99 query latency for aggregation queries, optimize TimescaleDB chunk exclusion
|
|
-- ================================================================================================
|
|
|
|
-- ================================================================================================
|
|
-- PART 1: ENHANCED COMPOSITE INDEXES FOR COMMON QUERY PATTERNS
|
|
-- ================================================================================================
|
|
|
|
-- Note: TimescaleDB hypertables do not support CONCURRENTLY, using regular CREATE INDEX
|
|
-- Optimize symbol-filtered aggregation queries (from paper trading validation)
|
|
-- Pattern: WHERE symbol = ? AND timestamp > ?
|
|
CREATE INDEX IF NOT EXISTS idx_ensemble_predictions_symbol_time
|
|
ON ensemble_predictions (symbol, timestamp DESC)
|
|
WHERE timestamp > NOW() - INTERVAL '30 days';
|
|
|
|
-- Optimize real-time dashboard queries (last 24 hours)
|
|
-- Pattern: WHERE timestamp > NOW() - INTERVAL '1 day'
|
|
-- Note: This is a partial index covering only recent data for faster scans
|
|
CREATE INDEX IF NOT EXISTS idx_ensemble_predictions_recent_24h
|
|
ON ensemble_predictions (timestamp DESC)
|
|
INCLUDE (ensemble_confidence, disagreement_rate, ensemble_action, symbol)
|
|
WHERE timestamp > NOW() - INTERVAL '24 hours';
|
|
|
|
-- Optimize model-specific queries (individual model performance)
|
|
-- Pattern: WHERE dqn_signal IS NOT NULL
|
|
CREATE INDEX IF NOT EXISTS idx_ensemble_predictions_dqn_active
|
|
ON ensemble_predictions (timestamp DESC)
|
|
WHERE dqn_signal IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_ensemble_predictions_ppo_active
|
|
ON ensemble_predictions (timestamp DESC)
|
|
WHERE ppo_signal IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_ensemble_predictions_mamba2_active
|
|
ON ensemble_predictions (timestamp DESC)
|
|
WHERE mamba2_signal IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_ensemble_predictions_tft_active
|
|
ON ensemble_predictions (timestamp DESC)
|
|
WHERE tft_signal IS NOT NULL;
|
|
|
|
-- Optimize order execution tracking (predictions that converted to orders)
|
|
CREATE INDEX IF NOT EXISTS idx_ensemble_predictions_executed
|
|
ON ensemble_predictions (timestamp DESC)
|
|
INCLUDE (order_id, executed_price, position_size, pnl)
|
|
WHERE order_id IS NOT NULL;
|
|
|
|
-- ================================================================================================
|
|
-- PART 2: MATERIALIZED VIEWS FOR SLOW AGGREGATION QUERIES
|
|
-- ================================================================================================
|
|
|
|
-- Real-time model activity summary (for debugging NULL model votes)
|
|
-- Refreshes every minute to catch inactive models quickly
|
|
DROP MATERIALIZED VIEW IF EXISTS model_activity_realtime CASCADE;
|
|
|
|
CREATE MATERIALIZED VIEW model_activity_realtime AS
|
|
SELECT
|
|
time_bucket('1 minute', timestamp) AS minute,
|
|
symbol,
|
|
COUNT(*) AS total_predictions,
|
|
COUNT(dqn_signal) AS dqn_active_count,
|
|
COUNT(ppo_signal) AS ppo_active_count,
|
|
COUNT(mamba2_signal) AS mamba2_active_count,
|
|
COUNT(tft_signal) AS tft_active_count,
|
|
ROUND(100.0 * COUNT(dqn_signal) / NULLIF(COUNT(*), 0), 2) AS dqn_active_pct,
|
|
ROUND(100.0 * COUNT(ppo_signal) / NULLIF(COUNT(*), 0), 2) AS ppo_active_pct,
|
|
ROUND(100.0 * COUNT(mamba2_signal) / NULLIF(COUNT(*), 0), 2) AS mamba2_active_pct,
|
|
ROUND(100.0 * COUNT(tft_signal) / NULLIF(COUNT(*), 0), 2) AS tft_active_pct,
|
|
AVG(ensemble_confidence) AS avg_confidence,
|
|
AVG(disagreement_rate) AS avg_disagreement
|
|
FROM ensemble_predictions
|
|
WHERE timestamp > NOW() - INTERVAL '1 hour'
|
|
GROUP BY minute, symbol
|
|
ORDER BY minute DESC;
|
|
|
|
CREATE INDEX ON model_activity_realtime (minute DESC);
|
|
CREATE INDEX ON model_activity_realtime (symbol);
|
|
|
|
COMMENT ON MATERIALIZED VIEW model_activity_realtime IS 'Real-time model activity tracking (last 1 hour, 1-minute buckets)';
|
|
|
|
-- Paper trading execution summary (for monitoring order conversion rate)
|
|
DROP MATERIALIZED VIEW IF EXISTS paper_trading_execution_summary CASCADE;
|
|
|
|
CREATE MATERIALIZED VIEW paper_trading_execution_summary AS
|
|
SELECT
|
|
time_bucket('5 minutes', timestamp) AS bucket,
|
|
symbol,
|
|
COUNT(*) AS total_predictions,
|
|
COUNT(order_id) AS executed_orders,
|
|
ROUND(100.0 * COUNT(order_id) / NULLIF(COUNT(*), 0), 2) AS execution_rate_pct,
|
|
COUNT(CASE WHEN pnl > 0 THEN 1 END) AS winning_trades,
|
|
COUNT(CASE WHEN pnl < 0 THEN 1 END) AS losing_trades,
|
|
COUNT(CASE WHEN pnl IS NOT NULL THEN 1 END) AS total_trades,
|
|
ROUND(100.0 * COUNT(CASE WHEN pnl > 0 THEN 1 END) / NULLIF(COUNT(CASE WHEN pnl IS NOT NULL THEN 1 END), 0), 2) AS win_rate_pct,
|
|
SUM(pnl) AS total_pnl,
|
|
AVG(pnl) AS avg_pnl,
|
|
STDDEV(pnl) AS stddev_pnl,
|
|
MIN(pnl) AS worst_trade,
|
|
MAX(pnl) AS best_trade
|
|
FROM ensemble_predictions
|
|
WHERE timestamp > NOW() - INTERVAL '24 hours'
|
|
GROUP BY bucket, symbol
|
|
ORDER BY bucket DESC;
|
|
|
|
CREATE INDEX ON paper_trading_execution_summary (bucket DESC);
|
|
CREATE INDEX ON paper_trading_execution_summary (symbol);
|
|
|
|
COMMENT ON MATERIALIZED VIEW paper_trading_execution_summary IS 'Paper trading execution rate and P&L summary (last 24 hours)';
|
|
|
|
-- ================================================================================================
|
|
-- PART 3: OPTIMIZED QUERY FUNCTIONS (PRE-COMPUTED AGGREGATIONS)
|
|
-- ================================================================================================
|
|
|
|
-- Fast aggregation function for real-time dashboard queries
|
|
-- Uses continuous aggregates instead of scanning raw table
|
|
CREATE OR REPLACE FUNCTION get_ensemble_performance_summary(
|
|
p_interval INTERVAL DEFAULT INTERVAL '1 day',
|
|
p_symbol VARCHAR(20) DEFAULT NULL
|
|
)
|
|
RETURNS TABLE (
|
|
avg_confidence DOUBLE PRECISION,
|
|
avg_disagreement DOUBLE PRECISION,
|
|
total_predictions BIGINT,
|
|
total_trades BIGINT,
|
|
win_rate DOUBLE PRECISION,
|
|
total_pnl NUMERIC,
|
|
avg_latency_us NUMERIC,
|
|
p99_latency_us DOUBLE PRECISION
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT
|
|
AVG(ep5m.avg_confidence)::DOUBLE PRECISION,
|
|
AVG(ep5m.avg_disagreement)::DOUBLE PRECISION,
|
|
SUM(ep5m.prediction_count)::BIGINT,
|
|
SUM(ep5m.total_trades)::BIGINT,
|
|
(100.0 * SUM(ep5m.winning_trades) / NULLIF(SUM(ep5m.total_trades), 0))::DOUBLE PRECISION,
|
|
SUM(ep5m.total_pnl),
|
|
AVG(ep5m.avg_latency_us),
|
|
MAX(ep5m.p99_latency_us)::DOUBLE PRECISION
|
|
FROM ensemble_performance_5min ep5m
|
|
WHERE ep5m.bucket > NOW() - p_interval
|
|
AND (p_symbol IS NULL OR ep5m.symbol = p_symbol);
|
|
END;
|
|
$$ LANGUAGE plpgsql STABLE;
|
|
|
|
COMMENT ON FUNCTION get_ensemble_performance_summary IS 'Fast aggregation using continuous aggregates (avoids raw table scan)';
|
|
|
|
-- Model activity health check function
|
|
-- Quickly identifies inactive models
|
|
CREATE OR REPLACE FUNCTION check_model_activity_health(
|
|
p_lookback_minutes INTEGER DEFAULT 60
|
|
)
|
|
RETURNS TABLE (
|
|
model_name VARCHAR(20),
|
|
is_active BOOLEAN,
|
|
last_prediction_time TIMESTAMPTZ,
|
|
minutes_since_last_prediction INTEGER,
|
|
predictions_in_window BIGINT,
|
|
activity_rate_pct DOUBLE PRECISION
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
WITH recent_predictions AS (
|
|
SELECT
|
|
timestamp,
|
|
dqn_signal IS NOT NULL AS dqn_active,
|
|
ppo_signal IS NOT NULL AS ppo_active,
|
|
mamba2_signal IS NOT NULL AS mamba2_active,
|
|
tft_signal IS NOT NULL AS tft_active
|
|
FROM ensemble_predictions
|
|
WHERE timestamp > NOW() - INTERVAL '1 minute' * p_lookback_minutes
|
|
),
|
|
model_stats AS (
|
|
SELECT
|
|
'DQN' AS model,
|
|
MAX(CASE WHEN dqn_active THEN timestamp END) AS last_pred,
|
|
COUNT(CASE WHEN dqn_active THEN 1 END) AS pred_count,
|
|
COUNT(*) AS total_count
|
|
FROM recent_predictions
|
|
UNION ALL
|
|
SELECT
|
|
'PPO',
|
|
MAX(CASE WHEN ppo_active THEN timestamp END),
|
|
COUNT(CASE WHEN ppo_active THEN 1 END),
|
|
COUNT(*)
|
|
FROM recent_predictions
|
|
UNION ALL
|
|
SELECT
|
|
'MAMBA-2',
|
|
MAX(CASE WHEN mamba2_active THEN timestamp END),
|
|
COUNT(CASE WHEN mamba2_active THEN 1 END),
|
|
COUNT(*)
|
|
FROM recent_predictions
|
|
UNION ALL
|
|
SELECT
|
|
'TFT',
|
|
MAX(CASE WHEN tft_active THEN timestamp END),
|
|
COUNT(CASE WHEN tft_active THEN 1 END),
|
|
COUNT(*)
|
|
FROM recent_predictions
|
|
)
|
|
SELECT
|
|
ms.model::VARCHAR(20),
|
|
(ms.pred_count > 0)::BOOLEAN,
|
|
ms.last_pred,
|
|
EXTRACT(EPOCH FROM (NOW() - COALESCE(ms.last_pred, NOW() - INTERVAL '1 year')))::INTEGER / 60,
|
|
ms.pred_count::BIGINT,
|
|
(100.0 * ms.pred_count / NULLIF(ms.total_count, 0))::DOUBLE PRECISION
|
|
FROM model_stats ms;
|
|
END;
|
|
$$ LANGUAGE plpgsql STABLE;
|
|
|
|
COMMENT ON FUNCTION check_model_activity_health IS 'Quickly identifies inactive models (NULL signal issue)';
|
|
|
|
-- ================================================================================================
|
|
-- PART 4: QUERY PERFORMANCE MONITORING
|
|
-- ================================================================================================
|
|
|
|
-- Create extension for query statistics if not exists
|
|
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
|
|
|
|
-- View for monitoring slow queries (updated from migration 023)
|
|
CREATE OR REPLACE VIEW ensemble_slow_queries AS
|
|
SELECT
|
|
LEFT(query, 150) AS query_preview,
|
|
calls,
|
|
ROUND(total_exec_time::NUMERIC / 1000.0, 2) AS total_time_sec,
|
|
ROUND(mean_exec_time::NUMERIC, 2) AS avg_time_ms,
|
|
ROUND(max_exec_time::NUMERIC, 2) AS max_time_ms,
|
|
ROUND(stddev_exec_time::NUMERIC, 2) AS stddev_time_ms,
|
|
rows / NULLIF(calls, 0) AS avg_rows_per_call,
|
|
ROUND(100.0 * shared_blks_hit / NULLIF(shared_blks_hit + shared_blks_read, 0), 2) AS cache_hit_ratio
|
|
FROM pg_stat_statements
|
|
WHERE query LIKE '%ensemble_predictions%'
|
|
OR query LIKE '%model_performance_attribution%'
|
|
OR query LIKE '%paper_trading_predictions%'
|
|
ORDER BY mean_exec_time DESC
|
|
LIMIT 30;
|
|
|
|
COMMENT ON VIEW ensemble_slow_queries IS 'Top 30 slowest ensemble/paper trading queries with cache hit ratio';
|
|
|
|
-- ================================================================================================
|
|
-- PART 5: VACUUM AND ANALYZE OPTIMIZATION
|
|
-- ================================================================================================
|
|
|
|
-- Optimize autovacuum settings for high-write tables
|
|
ALTER TABLE ensemble_predictions SET (
|
|
autovacuum_vacuum_scale_factor = 0.05, -- Vacuum when 5% of rows change (default 20%)
|
|
autovacuum_analyze_scale_factor = 0.025, -- Analyze when 2.5% change (default 10%)
|
|
autovacuum_vacuum_cost_delay = 10 -- Speed up vacuum (default 20ms)
|
|
);
|
|
|
|
ALTER TABLE model_performance_attribution SET (
|
|
autovacuum_vacuum_scale_factor = 0.05,
|
|
autovacuum_analyze_scale_factor = 0.025,
|
|
autovacuum_vacuum_cost_delay = 10
|
|
);
|
|
|
|
ALTER TABLE paper_trading_predictions SET (
|
|
autovacuum_vacuum_scale_factor = 0.05,
|
|
autovacuum_analyze_scale_factor = 0.025,
|
|
autovacuum_vacuum_cost_delay = 10
|
|
);
|
|
|
|
-- Force immediate vacuum and analyze
|
|
VACUUM ANALYZE ensemble_predictions;
|
|
VACUUM ANALYZE model_performance_attribution;
|
|
VACUUM ANALYZE paper_trading_predictions;
|
|
|
|
-- ================================================================================================
|
|
-- PART 6: GRANT PERMISSIONS
|
|
-- ================================================================================================
|
|
|
|
GRANT SELECT ON model_activity_realtime TO foxhunt;
|
|
GRANT SELECT ON paper_trading_execution_summary TO foxhunt;
|
|
GRANT SELECT ON ensemble_slow_queries TO foxhunt;
|
|
GRANT EXECUTE ON FUNCTION get_ensemble_performance_summary TO foxhunt;
|
|
GRANT EXECUTE ON FUNCTION check_model_activity_health TO foxhunt;
|
|
|
|
-- ================================================================================================
|
|
-- PART 7: REFRESH MATERIALIZED VIEWS
|
|
-- ================================================================================================
|
|
|
|
REFRESH MATERIALIZED VIEW model_activity_realtime;
|
|
REFRESH MATERIALIZED VIEW paper_trading_execution_summary;
|
|
|
|
-- ================================================================================================
|
|
-- END MIGRATION 025
|
|
-- ================================================================================================
|