-- ============================================================================ -- INVESTMENT SCHEMA - Tabla: daily_performance -- ============================================================================ -- Snapshots diarios de rendimiento de cuentas PAMM -- Usado para graficos, reportes y calculo de metricas -- ============================================================================ CREATE TABLE IF NOT EXISTS investment.daily_performance ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Relaciones account_id UUID NOT NULL REFERENCES investment.accounts(id) ON DELETE CASCADE, product_id UUID NOT NULL REFERENCES investment.products(id) ON DELETE CASCADE, -- Fecha del snapshot snapshot_date DATE NOT NULL, -- Balance opening_balance DECIMAL(20, 8) NOT NULL, closing_balance DECIMAL(20, 8) NOT NULL, -- Rendimiento del dia daily_pnl DECIMAL(20, 8) NOT NULL DEFAULT 0, daily_return_percentage DECIMAL(10, 6) NOT NULL DEFAULT 0, -- Rendimiento acumulado cumulative_pnl DECIMAL(20, 8) NOT NULL DEFAULT 0, cumulative_return_percentage DECIMAL(10, 6) NOT NULL DEFAULT 0, -- Movimientos del dia deposits DECIMAL(20, 8) NOT NULL DEFAULT 0, withdrawals DECIMAL(20, 8) NOT NULL DEFAULT 0, distributions_received DECIMAL(20, 8) NOT NULL DEFAULT 0, -- Metricas del agente de trading trades_executed INTEGER NOT NULL DEFAULT 0, winning_trades INTEGER NOT NULL DEFAULT 0, losing_trades INTEGER NOT NULL DEFAULT 0, win_rate DECIMAL(5, 2), -- Volatilidad y riesgo max_drawdown DECIMAL(10, 6), sharpe_ratio DECIMAL(10, 6), volatility DECIMAL(10, 6), -- High/Low del dia high_water_mark DECIMAL(20, 8), lowest_point DECIMAL(20, 8), -- Metadata del snapshot snapshot_source VARCHAR(50) DEFAULT 'cron', -- 'cron', 'manual', 'system' metadata JSONB DEFAULT '{}', -- Timestamps created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Constraints CONSTRAINT uq_daily_performance_account_date UNIQUE(account_id, snapshot_date), CONSTRAINT chk_valid_balances CHECK (opening_balance >= 0 AND closing_balance >= 0), CONSTRAINT chk_valid_movements CHECK (deposits >= 0 AND withdrawals >= 0), CONSTRAINT chk_valid_trades CHECK ( trades_executed >= 0 AND winning_trades >= 0 AND losing_trades >= 0 AND winning_trades + losing_trades <= trades_executed ), CONSTRAINT chk_valid_win_rate CHECK (win_rate IS NULL OR (win_rate >= 0 AND win_rate <= 100)) ); -- Indices CREATE INDEX idx_daily_performance_account ON investment.daily_performance(account_id); CREATE INDEX idx_daily_performance_product ON investment.daily_performance(product_id); CREATE INDEX idx_daily_performance_date ON investment.daily_performance(snapshot_date DESC); CREATE INDEX idx_daily_performance_account_date ON investment.daily_performance(account_id, snapshot_date DESC); -- Index for recent performance (removed time-based predicate for immutability) CREATE INDEX idx_daily_performance_recent ON investment.daily_performance(account_id, snapshot_date DESC); -- Comentarios COMMENT ON TABLE investment.daily_performance IS 'Snapshots diarios de rendimiento de cuentas PAMM'; COMMENT ON COLUMN investment.daily_performance.snapshot_date IS 'Fecha del snapshot (una entrada por dia por cuenta)'; COMMENT ON COLUMN investment.daily_performance.daily_return_percentage IS 'Retorno del dia como porcentaje'; COMMENT ON COLUMN investment.daily_performance.cumulative_return_percentage IS 'Retorno acumulado desde apertura de cuenta'; COMMENT ON COLUMN investment.daily_performance.max_drawdown IS 'Maximo drawdown del dia'; COMMENT ON COLUMN investment.daily_performance.high_water_mark IS 'Punto mas alto alcanzado'; -- Vista para resumen mensual CREATE OR REPLACE VIEW investment.v_monthly_performance AS SELECT account_id, product_id, DATE_TRUNC('month', snapshot_date) AS month, MIN(opening_balance) AS month_opening, MAX(closing_balance) AS month_closing, SUM(daily_pnl) AS total_pnl, AVG(daily_return_percentage) AS avg_daily_return, SUM(deposits) AS total_deposits, SUM(withdrawals) AS total_withdrawals, SUM(distributions_received) AS total_distributions, SUM(trades_executed) AS total_trades, SUM(winning_trades) AS total_winning, SUM(losing_trades) AS total_losing, CASE WHEN SUM(winning_trades) + SUM(losing_trades) > 0 THEN ROUND(SUM(winning_trades)::DECIMAL / (SUM(winning_trades) + SUM(losing_trades)) * 100, 2) ELSE NULL END AS monthly_win_rate, MIN(lowest_point) AS monthly_low, MAX(high_water_mark) AS monthly_high, COUNT(*) AS trading_days FROM investment.daily_performance GROUP BY account_id, product_id, DATE_TRUNC('month', snapshot_date); COMMENT ON VIEW investment.v_monthly_performance IS 'Resumen mensual de rendimiento agregado';