Files
foxhunt/docs/ENSEMBLE_AUDIT_QUERIES.sql
jgrusewski 650b3894c6 🚀 Wave 160 Phase 5: Complete ML Ensemble + Production Deployment (27 Agents)
## Executive Summary
Deployed 27 parallel agents: all 6 models operational, ensemble working, adaptive
strategy integrated, hyperparameter tuning automated, TFT fixed, critical blocker
resolved (DbnSequenceLoader 99.85% memory reduction 40.6GB→61MB).

## Critical Fixes
- Agent 85: DbnSequenceLoader memory fix (UNBLOCKED all ML training)
- Agent 79: TFT 5 critical bugs fixed
- Agent 86: Adaptive strategy integration (regime-aware ensemble)
- Agent 88: Liquid NN API fix (14 compilation errors)
- Agent 89: Paper trading deployment (LIVE, 3-model ensemble)

## Infrastructure
- Database: 2,127 writes/sec (212% of target)
- Memory: DQN 192MB, PPO 288MB, TFT 384MB (all within targets)
- Ensemble: Sharpe 10.68, latency 35μs, throughput >20K/sec
- Monitoring: 22 alerts, PagerDuty integration

## Files: 193 changed, +70,250 insertions, -414 deletions

🤖 Generated with Claude Code - Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-14 18:41:48 +02:00

500 lines
18 KiB
SQL

-- ================================================================================================
-- Ensemble Audit Analysis Queries
-- Production-ready SQL queries for ensemble performance analysis and debugging
-- ================================================================================================
-- ================================================================================================
-- TOP PERFORMING MODELS (LAST 24 HOURS)
-- ================================================================================================
-- Query 1: Get top 5 models by Sharpe ratio (last 24 hours)
SELECT * FROM get_top_models_24h(NULL, 5);
-- Query 2: Get top performers for specific symbol
SELECT * FROM get_top_models_24h('ES.FUT', 10);
-- Query 3: Manual calculation for custom time windows
SELECT
model_id,
symbol,
COUNT(*) as predictions,
AVG(accuracy) as avg_accuracy,
AVG(sharpe_ratio) as avg_sharpe,
SUM(total_pnl) as cumulative_pnl,
AVG(avg_weight) as avg_ensemble_weight
FROM model_performance_attribution
WHERE
timestamp >= NOW() - INTERVAL '7 days'
AND window_hours = 24
GROUP BY model_id, symbol
ORDER BY avg_sharpe DESC NULLS LAST
LIMIT 10;
-- ================================================================================================
-- MODEL CORRELATION MATRIX (LAST 7 DAYS)
-- ================================================================================================
-- Query 4: Calculate pairwise model correlations
SELECT * FROM calculate_model_correlation_7d(NULL);
-- Query 5: Model correlation for specific symbol
SELECT * FROM calculate_model_correlation_7d('NQ.FUT');
-- Query 6: Visual correlation matrix (pivot format)
WITH correlation_data AS (
SELECT * FROM calculate_model_correlation_7d(NULL)
)
SELECT
model_a,
MAX(CASE WHEN model_b = 'PPO' THEN correlation END) as ppo_corr,
MAX(CASE WHEN model_b = 'MAMBA2' THEN correlation END) as mamba2_corr,
MAX(CASE WHEN model_b = 'TFT' THEN correlation END) as tft_corr
FROM correlation_data
WHERE model_a IN ('DQN', 'PPO', 'MAMBA2')
GROUP BY model_a
ORDER BY model_a;
-- ================================================================================================
-- ENSEMBLE VS INDIVIDUAL MODEL PERFORMANCE (LAST 30 DAYS)
-- ================================================================================================
-- Query 7: Compare ensemble Sharpe ratio to individual models
WITH ensemble_performance AS (
SELECT
symbol,
COUNT(*) as total_predictions,
AVG(ensemble_confidence) as avg_confidence,
SUM(pnl) as total_pnl,
STDDEV(pnl::DOUBLE PRECISION) as pnl_std,
AVG(pnl::DOUBLE PRECISION) / NULLIF(STDDEV(pnl::DOUBLE PRECISION), 0) as sharpe_approx
FROM ensemble_predictions
WHERE
timestamp >= NOW() - INTERVAL '30 days'
AND pnl IS NOT NULL
GROUP BY symbol
),
model_performance AS (
SELECT
model_id,
symbol,
AVG(sharpe_ratio) as avg_sharpe,
SUM(total_pnl) as total_pnl
FROM model_performance_attribution
WHERE
timestamp >= NOW() - INTERVAL '30 days'
AND window_hours = 24
GROUP BY model_id, symbol
)
SELECT
ep.symbol,
ep.total_predictions as ensemble_predictions,
ep.sharpe_approx as ensemble_sharpe,
ep.total_pnl as ensemble_pnl,
mp_dqn.avg_sharpe as dqn_sharpe,
mp_ppo.avg_sharpe as ppo_sharpe,
mp_mamba2.avg_sharpe as mamba2_sharpe,
mp_tft.avg_sharpe as tft_sharpe,
GREATEST(
COALESCE(mp_dqn.avg_sharpe, 0),
COALESCE(mp_ppo.avg_sharpe, 0),
COALESCE(mp_mamba2.avg_sharpe, 0),
COALESCE(mp_tft.avg_sharpe, 0)
) as best_individual_sharpe,
(ep.sharpe_approx - GREATEST(
COALESCE(mp_dqn.avg_sharpe, 0),
COALESCE(mp_ppo.avg_sharpe, 0),
COALESCE(mp_mamba2.avg_sharpe, 0),
COALESCE(mp_tft.avg_sharpe, 0)
)) as ensemble_lift
FROM ensemble_performance ep
LEFT JOIN model_performance mp_dqn ON ep.symbol = mp_dqn.symbol AND mp_dqn.model_id = 'DQN'
LEFT JOIN model_performance mp_ppo ON ep.symbol = mp_ppo.symbol AND mp_ppo.model_id = 'PPO'
LEFT JOIN model_performance mp_mamba2 ON ep.symbol = mp_mamba2.symbol AND mp_mamba2.model_id = 'MAMBA2'
LEFT JOIN model_performance mp_tft ON ep.symbol = mp_tft.symbol AND mp_tft.model_id = 'TFT'
ORDER BY ep.sharpe_approx DESC NULLS LAST;
-- ================================================================================================
-- HIGH DISAGREEMENT EVENTS (LAST 24 HOURS)
-- ================================================================================================
-- Query 8: Get high disagreement events (threshold = 50%)
SELECT * FROM get_high_disagreement_events_24h(NULL, 0.5, 100);
-- Query 9: Very high disagreement (threshold = 70%)
SELECT * FROM get_high_disagreement_events_24h(NULL, 0.7, 50);
-- Query 10: Disagreement with market context (price volatility)
SELECT
ep.timestamp,
ep.symbol,
ep.ensemble_action,
ep.disagreement_rate,
ep.dqn_vote,
ep.ppo_vote,
ep.mamba2_vote,
ep.tft_vote,
ep.executed_price,
ep.pnl,
-- Categorize disagreement level
CASE
WHEN ep.disagreement_rate >= 0.75 THEN 'CRITICAL'
WHEN ep.disagreement_rate >= 0.5 THEN 'HIGH'
WHEN ep.disagreement_rate >= 0.25 THEN 'MODERATE'
ELSE 'LOW'
END as disagreement_level
FROM ensemble_predictions ep
WHERE
ep.timestamp >= NOW() - INTERVAL '24 hours'
AND ep.disagreement_rate >= 0.25
ORDER BY ep.disagreement_rate DESC, ep.timestamp DESC
LIMIT 100;
-- ================================================================================================
-- P&L ATTRIBUTION BY MODEL (LAST 7 DAYS)
-- ================================================================================================
-- Query 11: Total P&L contribution per model
SELECT
model_id,
symbol,
COUNT(*) as trades_with_contribution,
SUM(total_pnl) / 100.0 as total_pnl_dollars, -- Convert cents to dollars
AVG(total_pnl) / 100.0 as avg_pnl_per_trade_dollars,
AVG(avg_weight) as avg_ensemble_weight,
SUM(total_pnl) / NULLIF(AVG(avg_weight), 0) / 100.0 as pnl_per_unit_weight
FROM model_performance_attribution
WHERE
timestamp >= NOW() - INTERVAL '7 days'
AND window_hours = 24
GROUP BY model_id, symbol
ORDER BY total_pnl_dollars DESC;
-- Query 12: Daily P&L attribution breakdown
SELECT
DATE_TRUNC('day', timestamp) as trading_day,
model_id,
SUM(total_pnl) / 100.0 as daily_pnl_dollars,
AVG(accuracy) as avg_accuracy,
AVG(sharpe_ratio) as avg_sharpe
FROM model_performance_attribution
WHERE
timestamp >= NOW() - INTERVAL '7 days'
AND window_hours = 24
GROUP BY trading_day, model_id
ORDER BY trading_day DESC, daily_pnl_dollars DESC;
-- Query 13: Per-prediction P&L attribution (detailed view)
SELECT
ep.timestamp,
ep.symbol,
ep.ensemble_action,
ep.order_id,
ep.pnl / 100.0 as ensemble_pnl_dollars,
-- Approximate per-model P&L based on weights
(ep.pnl * ep.dqn_weight) / 100.0 as dqn_attributed_pnl_dollars,
(ep.pnl * ep.ppo_weight) / 100.0 as ppo_attributed_pnl_dollars,
(ep.pnl * ep.mamba2_weight) / 100.0 as mamba2_attributed_pnl_dollars,
(ep.pnl * ep.tft_weight) / 100.0 as tft_attributed_pnl_dollars,
ep.commission / 100.0 as commission_dollars,
ep.slippage_bps as slippage_basis_points
FROM ensemble_predictions ep
WHERE
ep.timestamp >= NOW() - INTERVAL '7 days'
AND ep.pnl IS NOT NULL
ORDER BY ep.timestamp DESC
LIMIT 1000;
-- ================================================================================================
-- A/B TEST ANALYSIS
-- ================================================================================================
-- Query 14: A/B test performance comparison (active tests)
WITH ab_metrics AS (
SELECT
ab_test_id,
ab_group,
COUNT(*) as predictions,
AVG(ensemble_confidence) as avg_confidence,
AVG(disagreement_rate) as avg_disagreement,
SUM(pnl) / 100.0 as total_pnl_dollars,
STDDEV(pnl::DOUBLE PRECISION) as pnl_std,
AVG(pnl::DOUBLE PRECISION) / NULLIF(STDDEV(pnl::DOUBLE PRECISION), 0) as sharpe_approx,
COUNT(CASE WHEN pnl > 0 THEN 1 END) as winning_trades,
COUNT(CASE WHEN pnl IS NOT NULL THEN 1 END) as total_trades
FROM ensemble_predictions
WHERE
ab_test_id IS NOT NULL
AND timestamp >= NOW() - INTERVAL '7 days'
GROUP BY ab_test_id, ab_group
)
SELECT
test.test_name,
control.predictions as control_predictions,
treatment.predictions as treatment_predictions,
control.sharpe_approx as control_sharpe,
treatment.sharpe_approx as treatment_sharpe,
(treatment.sharpe_approx - control.sharpe_approx) as sharpe_diff,
(treatment.sharpe_approx - control.sharpe_approx) / NULLIF(control.sharpe_approx, 0) * 100 as sharpe_lift_percent,
control.total_pnl_dollars as control_pnl,
treatment.total_pnl_dollars as treatment_pnl,
(treatment.total_pnl_dollars - control.total_pnl_dollars) as pnl_diff,
control.winning_trades::FLOAT / NULLIF(control.total_trades, 0) as control_win_rate,
treatment.winning_trades::FLOAT / NULLIF(treatment.total_trades, 0) as treatment_win_rate
FROM ab_test_experiments test
LEFT JOIN ab_metrics control ON test.test_id = control.ab_test_id AND control.ab_group = 'control'
LEFT JOIN ab_metrics treatment ON test.test_id = treatment.ab_test_id AND treatment.ab_group = 'treatment'
WHERE test.status = 'running'
ORDER BY test.started_at DESC;
-- Query 15: Statistical significance test (Welch's t-test approximation)
-- NOTE: For production, use actual statistical libraries; this is a simplified version
WITH ab_pnl_samples AS (
SELECT
ab_test_id,
ab_group,
pnl::DOUBLE PRECISION as pnl_sample
FROM ensemble_predictions
WHERE
ab_test_id IS NOT NULL
AND pnl IS NOT NULL
AND timestamp >= NOW() - INTERVAL '7 days'
),
ab_stats AS (
SELECT
ab_test_id,
ab_group,
COUNT(*) as n,
AVG(pnl_sample) as mean_pnl,
STDDEV(pnl_sample) as std_pnl
FROM ab_pnl_samples
GROUP BY ab_test_id, ab_group
)
SELECT
test.test_name,
control.n as control_n,
treatment.n as treatment_n,
control.mean_pnl / 100.0 as control_mean_pnl_dollars,
treatment.mean_pnl / 100.0 as treatment_mean_pnl_dollars,
(treatment.mean_pnl - control.mean_pnl) / 100.0 as mean_pnl_diff_dollars,
control.std_pnl / 100.0 as control_std_dollars,
treatment.std_pnl / 100.0 as treatment_std_dollars,
-- Welch's t-statistic approximation
(treatment.mean_pnl - control.mean_pnl) /
SQRT((control.std_pnl * control.std_pnl) / control.n +
(treatment.std_pnl * treatment.std_pnl) / treatment.n) as t_statistic,
CASE
WHEN ABS((treatment.mean_pnl - control.mean_pnl) /
SQRT((control.std_pnl * control.std_pnl) / control.n +
(treatment.std_pnl * treatment.std_pnl) / treatment.n)) > 1.96
THEN 'SIGNIFICANT (p < 0.05)'
ELSE 'NOT SIGNIFICANT'
END as significance_95pct
FROM ab_test_experiments test
LEFT JOIN ab_stats control ON test.test_id = control.ab_test_id AND control.ab_group = 'control'
LEFT JOIN ab_stats treatment ON test.test_id = treatment.ab_test_id AND treatment.ab_group = 'treatment'
WHERE test.status = 'running'
ORDER BY test.started_at DESC;
-- ================================================================================================
-- LATENCY ANALYSIS
-- ================================================================================================
-- Query 16: P50/P95/P99 inference latency by symbol
SELECT
symbol,
COUNT(*) as predictions,
PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY inference_latency_us) as p50_latency_us,
PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY inference_latency_us) as p95_latency_us,
PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY inference_latency_us) as p99_latency_us,
AVG(inference_latency_us) as avg_latency_us,
MAX(inference_latency_us) as max_latency_us
FROM ensemble_predictions
WHERE
timestamp >= NOW() - INTERVAL '24 hours'
AND inference_latency_us IS NOT NULL
GROUP BY symbol
ORDER BY p99_latency_us DESC;
-- Query 17: Aggregation latency distribution
SELECT
symbol,
COUNT(*) as predictions,
PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY aggregation_latency_us) as p50_agg_us,
PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY aggregation_latency_us) as p95_agg_us,
PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY aggregation_latency_us) as p99_agg_us,
AVG(aggregation_latency_us) as avg_agg_us
FROM ensemble_predictions
WHERE
timestamp >= NOW() - INTERVAL '24 hours'
AND aggregation_latency_us IS NOT NULL
GROUP BY symbol
ORDER BY p99_agg_us DESC;
-- ================================================================================================
-- CHECKPOINT TRACKING
-- ================================================================================================
-- Query 18: Active checkpoints by model
SELECT DISTINCT ON (model_id, symbol)
CASE
WHEN dqn_checkpoint_id IS NOT NULL THEN 'DQN'
WHEN ppo_checkpoint_id IS NOT NULL THEN 'PPO'
WHEN mamba2_checkpoint_id IS NOT NULL THEN 'MAMBA2'
WHEN tft_checkpoint_id IS NOT NULL THEN 'TFT'
END as model_id,
symbol,
COALESCE(dqn_checkpoint_id, ppo_checkpoint_id, mamba2_checkpoint_id, tft_checkpoint_id) as checkpoint_id,
timestamp as last_used_at
FROM ensemble_predictions
WHERE timestamp >= NOW() - INTERVAL '24 hours'
ORDER BY model_id, symbol, timestamp DESC;
-- Query 19: Checkpoint performance comparison
WITH checkpoint_metrics AS (
SELECT
CASE
WHEN dqn_checkpoint_id IS NOT NULL THEN 'DQN'
WHEN ppo_checkpoint_id IS NOT NULL THEN 'PPO'
WHEN mamba2_checkpoint_id IS NOT NULL THEN 'MAMBA2'
WHEN tft_checkpoint_id IS NOT NULL THEN 'TFT'
END as model_id,
COALESCE(dqn_checkpoint_id, ppo_checkpoint_id, mamba2_checkpoint_id, tft_checkpoint_id) as checkpoint_id,
COUNT(*) as predictions,
AVG(ensemble_confidence) as avg_confidence,
SUM(pnl) / 100.0 as total_pnl_dollars
FROM ensemble_predictions
WHERE
timestamp >= NOW() - INTERVAL '7 days'
AND pnl IS NOT NULL
GROUP BY model_id, checkpoint_id
)
SELECT *
FROM checkpoint_metrics
ORDER BY model_id, total_pnl_dollars DESC;
-- ================================================================================================
-- CONTINUOUS AGGREGATE VIEWS (PRE-COMPUTED)
-- ================================================================================================
-- Query 20: Hourly ensemble performance (pre-aggregated)
SELECT
bucket,
symbol,
ensemble_action,
prediction_count,
avg_confidence,
avg_disagreement,
avg_latency_us,
total_pnl / 100.0 as total_pnl_dollars,
CASE WHEN total_trades > 0 THEN winning_trades::FLOAT / total_trades ELSE 0 END as win_rate
FROM ensemble_performance_hourly
WHERE bucket >= NOW() - INTERVAL '24 hours'
ORDER BY bucket DESC, symbol;
-- Query 21: Daily model performance (pre-aggregated)
SELECT
bucket,
model_id,
symbol,
total_predictions,
avg_accuracy,
total_pnl / 100.0 as total_pnl_dollars,
avg_sharpe_ratio,
avg_weight,
avg_disagreement_rate
FROM model_performance_daily
WHERE bucket >= NOW() - INTERVAL '7 days'
ORDER BY bucket DESC, avg_sharpe_ratio DESC NULLS LAST;
-- ================================================================================================
-- DEBUGGING QUERIES
-- ================================================================================================
-- Query 22: Failed predictions (high disagreement + negative P&L)
SELECT
timestamp,
symbol,
ensemble_action,
ensemble_confidence,
disagreement_rate,
pnl / 100.0 as pnl_dollars,
dqn_vote,
ppo_vote,
mamba2_vote,
tft_vote,
feature_snapshot
FROM ensemble_predictions
WHERE
timestamp >= NOW() - INTERVAL '7 days'
AND pnl IS NOT NULL
AND pnl < 0
AND disagreement_rate > 0.5
ORDER BY pnl ASC
LIMIT 50;
-- Query 23: Model weight evolution over time
SELECT
DATE_TRUNC('hour', timestamp) as hour,
model_id,
AVG(avg_weight) as avg_weight
FROM model_performance_attribution
WHERE
timestamp >= NOW() - INTERVAL '7 days'
AND window_hours = 1
GROUP BY hour, model_id
ORDER BY hour DESC, model_id;
-- Query 24: Data quality checks (missing model votes)
SELECT
COUNT(*) as total_predictions,
COUNT(dqn_signal) as dqn_present,
COUNT(ppo_signal) as ppo_present,
COUNT(mamba2_signal) as mamba2_present,
COUNT(tft_signal) as tft_present,
COUNT(*) - COUNT(dqn_signal) as dqn_missing,
COUNT(*) - COUNT(ppo_signal) as ppo_missing,
COUNT(*) - COUNT(mamba2_signal) as mamba2_missing,
COUNT(*) - COUNT(tft_signal) as tft_missing
FROM ensemble_predictions
WHERE timestamp >= NOW() - INTERVAL '24 hours';
-- ================================================================================================
-- PERFORMANCE OPTIMIZATION QUERIES
-- ================================================================================================
-- Query 25: Index usage statistics
SELECT
schemaname,
tablename,
indexname,
idx_scan as index_scans,
idx_tup_read as tuples_read,
idx_tup_fetch as tuples_fetched
FROM pg_stat_user_indexes
WHERE schemaname = 'public'
AND tablename IN ('ensemble_predictions', 'model_performance_attribution')
ORDER BY idx_scan DESC;
-- Query 26: Table size and compression stats
SELECT
hypertable_name,
table_bytes,
index_bytes,
toast_bytes,
total_bytes,
pg_size_pretty(total_bytes) as total_size,
compression_enabled,
compressed_total_bytes,
pg_size_pretty(compressed_total_bytes) as compressed_size,
CASE
WHEN total_bytes > 0 THEN
ROUND(100.0 * (1 - compressed_total_bytes::FLOAT / total_bytes), 2)
ELSE 0
END as compression_ratio_percent
FROM timescaledb_information.hypertable
WHERE hypertable_name IN ('ensemble_predictions', 'model_performance_attribution');
-- ================================================================================================
-- END OF ANALYSIS QUERIES
-- ================================================================================================