-- 010_compliance_audit_trails.sql -- SOX and MiFID II Compliance Audit Trail Implementation -- Critical for production deployment - regulatory compliance -- Enable required extensions CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "btree_gin"; -- SOX Compliance: Trade Activity Audit Trail -- Tracks all trading activities for Sarbanes-Oxley compliance CREATE TABLE sox_trade_audit ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), trade_id UUID NOT NULL, user_id UUID REFERENCES users(id), session_id UUID, -- Trade Details (SOX Section 404 - Internal Controls) symbol VARCHAR(20) NOT NULL, side VARCHAR(10) NOT NULL CHECK (side IN ('BUY', 'SELL', 'SHORT', 'COVER')), quantity DECIMAL(18, 8) NOT NULL, price DECIMAL(18, 8), order_type VARCHAR(20) NOT NULL, time_in_force VARCHAR(10), -- SOX Financial Reporting Requirements trade_value DECIMAL(20, 8) NOT NULL, commission DECIMAL(10, 4), regulatory_fees DECIMAL(10, 4), net_amount DECIMAL(20, 8) NOT NULL, currency VARCHAR(3) NOT NULL DEFAULT 'USD', -- Timing and Status (SOX Section 302 - CEO/CFO Certification) order_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, execution_timestamp TIMESTAMP WITH TIME ZONE, settlement_date DATE, trade_status VARCHAR(20) NOT NULL CHECK (trade_status IN ('PENDING', 'FILLED', 'PARTIAL', 'CANCELLED', 'REJECTED', 'EXPIRED')), -- Risk and Compliance risk_assessment JSONB, compliance_flags JSONB, position_limit_check BOOLEAN DEFAULT false, regulatory_approval_required BOOLEAN DEFAULT false, -- Audit Trail (SOX Section 404) created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), audit_version INTEGER DEFAULT 1, change_reason TEXT, -- Digital Signature for Integrity audit_hash VARCHAR(64) NOT NULL, CONSTRAINT positive_quantity CHECK (quantity > 0), CONSTRAINT valid_trade_value CHECK (trade_value != 0) ); -- MiFID II Compliance: Transaction Reporting -- European Markets in Financial Instruments Directive II compliance CREATE TABLE mifid_transaction_report ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), trade_id UUID NOT NULL, -- MiFID II Article 26 - Transaction Reporting Fields trading_venue VARCHAR(100), instrument_id VARCHAR(50) NOT NULL, instrument_classification VARCHAR(10), -- EQTY, BOND, DERV, etc. isin_code VARCHAR(12), currency VARCHAR(3) NOT NULL, -- Price and Quantity (MiFID II RTS 22) price DECIMAL(18, 8), price_notation VARCHAR(10), -- MONE, PERC, YIEL, etc. quantity DECIMAL(18, 8) NOT NULL, quantity_notation VARCHAR(10), -- UNIT, MONE, etc. -- Venue and Counterparty Information execution_venue VARCHAR(100), venue_of_publication VARCHAR(100), country_of_branch VARCHAR(2), -- ISO 3166-1 alpha-2 -- Investment Decision and Execution investment_decision_within_firm VARCHAR(20), execution_within_firm VARCHAR(20), client_identification VARCHAR(50), decision_maker_code VARCHAR(20), -- Best Execution (MiFID II Article 27) best_execution_venue VARCHAR(100), execution_quality_factors JSONB, price_improvement DECIMAL(10, 6), likelihood_of_execution DECIMAL(5, 4), likelihood_of_settlement DECIMAL(5, 4), -- Timing Requirements (MiFID II RTS 22) transaction_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, publication_timestamp TIMESTAMP WITH TIME ZONE, reporting_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), -- Flags and Status large_in_scale BOOLEAN DEFAULT false, illiquid_instrument BOOLEAN DEFAULT false, size_specific_to_instrument BOOLEAN DEFAULT false, -- Compliance Status reporting_status VARCHAR(20) DEFAULT 'PENDING' CHECK (reporting_status IN ('PENDING', 'SUBMITTED', 'ACCEPTED', 'REJECTED', 'RESUBMITTED')), regulator_submission_id VARCHAR(100), submission_timestamp TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() ); -- Position Limits Compliance (MiFID II Article 57) CREATE TABLE position_limits_audit ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID REFERENCES users(id), -- Position Information instrument_id VARCHAR(50) NOT NULL, instrument_type VARCHAR(20) NOT NULL, position_size DECIMAL(18, 8) NOT NULL, position_direction VARCHAR(10) NOT NULL CHECK (position_direction IN ('LONG', 'SHORT', 'NET')), -- Limit Configuration position_limit DECIMAL(18, 8) NOT NULL, limit_type VARCHAR(20) NOT NULL CHECK (limit_type IN ('INDIVIDUAL', 'FIRM', 'REGULATORY')), limit_period VARCHAR(10) NOT NULL CHECK (limit_period IN ('DAILY', 'WEEKLY', 'MONTHLY', 'ONGOING')), -- Breach Detection limit_utilization DECIMAL(5, 4) NOT NULL, -- Percentage of limit used is_breach BOOLEAN NOT NULL DEFAULT false, breach_amount DECIMAL(18, 8), breach_percentage DECIMAL(5, 4), -- Risk Assessment risk_score DECIMAL(5, 2), risk_category VARCHAR(20), escalation_required BOOLEAN DEFAULT false, -- Timestamps assessment_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), position_timestamp TIMESTAMP WITH TIME ZONE NOT NULL, -- Actions Taken action_taken VARCHAR(500), approved_by UUID REFERENCES users(id), approval_timestamp TIMESTAMP WITH TIME ZONE ); -- Kill Switch Audit Trail (Circuit Breaker System) CREATE TABLE kill_switch_audit ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), -- Kill Switch Event switch_type VARCHAR(20) NOT NULL CHECK (switch_type IN ('MANUAL', 'AUTOMATIC', 'REGULATORY', 'RISK', 'TECHNICAL')), trigger_reason VARCHAR(500) NOT NULL, severity_level VARCHAR(10) NOT NULL CHECK (severity_level IN ('LOW', 'MEDIUM', 'HIGH', 'CRITICAL')), -- User and System Context triggered_by_user UUID REFERENCES users(id), system_component VARCHAR(100), affected_systems JSONB, -- Array of affected system components -- Risk Metrics at Time of Trigger portfolio_value DECIMAL(20, 8), daily_pnl DECIMAL(20, 8), var_breach_amount DECIMAL(20, 8), active_positions INTEGER, pending_orders INTEGER, -- Actions Taken positions_closed INTEGER DEFAULT 0, orders_cancelled INTEGER DEFAULT 0, systems_halted JSONB, -- Array of halted systems -- Timing trigger_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), resolution_timestamp TIMESTAMP WITH TIME ZONE, downtime_duration INTERVAL, -- Recovery Process recovery_steps JSONB, recovery_approved_by UUID REFERENCES users(id), recovery_timestamp TIMESTAMP WITH TIME ZONE, -- Compliance and Reporting regulatory_notification_sent BOOLEAN DEFAULT false, incident_report_filed BOOLEAN DEFAULT false, external_reporting_required BOOLEAN DEFAULT false, -- Post-Incident Analysis root_cause_analysis TEXT, preventive_measures TEXT, system_improvements JSONB ); -- Best Execution Analysis (MiFID II Article 27) CREATE TABLE best_execution_analysis ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), trade_id UUID NOT NULL, -- Execution Venues Considered primary_venue VARCHAR(100) NOT NULL, alternative_venues JSONB, -- Array of venues considered -- Execution Quality Factors price_factor_score DECIMAL(5, 4), cost_factor_score DECIMAL(5, 4), speed_factor_score DECIMAL(5, 4), likelihood_execution_score DECIMAL(5, 4), likelihood_settlement_score DECIMAL(5, 4), size_factor_score DECIMAL(5, 4), nature_factor_score DECIMAL(5, 4), -- Overall Best Execution Score overall_score DECIMAL(5, 4) NOT NULL, execution_quality_ranking INTEGER, -- Price Improvement Analysis reference_price DECIMAL(18, 8), execution_price DECIMAL(18, 8), price_improvement_amount DECIMAL(18, 8), price_improvement_percentage DECIMAL(5, 4), -- Cost Analysis explicit_costs DECIMAL(10, 4), -- Commissions, fees implicit_costs DECIMAL(10, 4), -- Spread, market impact total_transaction_costs DECIMAL(10, 4), -- Market Conditions market_volatility DECIMAL(5, 4), market_liquidity DECIMAL(5, 4), time_of_day_factor DECIMAL(5, 4), -- Analysis Timestamp analysis_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), -- Quality Assessment execution_quality_grade VARCHAR(5) CHECK (execution_quality_grade IN ('A+', 'A', 'A-', 'B+', 'B', 'B-', 'C+', 'C', 'C-', 'D', 'F')), meets_best_execution BOOLEAN NOT NULL, improvement_recommendations TEXT ); -- Create indexes for performance and compliance queries CREATE INDEX idx_sox_trade_audit_user_time ON sox_trade_audit(user_id, order_timestamp); CREATE INDEX idx_sox_trade_audit_symbol_time ON sox_trade_audit(symbol, order_timestamp); CREATE INDEX idx_sox_trade_audit_status ON sox_trade_audit(trade_status); CREATE INDEX idx_sox_trade_audit_hash ON sox_trade_audit(audit_hash); CREATE INDEX idx_mifid_transaction_instrument ON mifid_transaction_report(instrument_id, transaction_timestamp); CREATE INDEX idx_mifid_transaction_venue ON mifid_transaction_report(trading_venue, transaction_timestamp); CREATE INDEX idx_mifid_transaction_status ON mifid_transaction_report(reporting_status); CREATE INDEX idx_position_limits_user_instrument ON position_limits_audit(user_id, instrument_id, assessment_timestamp); CREATE INDEX idx_position_limits_breach ON position_limits_audit(is_breach, assessment_timestamp); CREATE INDEX idx_position_limits_utilization ON position_limits_audit(limit_utilization DESC); CREATE INDEX idx_kill_switch_type_time ON kill_switch_audit(switch_type, trigger_timestamp); CREATE INDEX idx_kill_switch_severity ON kill_switch_audit(severity_level, trigger_timestamp); CREATE INDEX idx_kill_switch_user ON kill_switch_audit(triggered_by_user, trigger_timestamp); CREATE INDEX idx_best_execution_trade ON best_execution_analysis(trade_id); CREATE INDEX idx_best_execution_quality ON best_execution_analysis(execution_quality_grade, analysis_timestamp); CREATE INDEX idx_best_execution_venue ON best_execution_analysis(primary_venue, analysis_timestamp); -- Row Level Security (RLS) for compliance data ALTER TABLE sox_trade_audit ENABLE ROW LEVEL SECURITY; ALTER TABLE mifid_transaction_report ENABLE ROW LEVEL SECURITY; ALTER TABLE position_limits_audit ENABLE ROW LEVEL SECURITY; ALTER TABLE kill_switch_audit ENABLE ROW LEVEL SECURITY; ALTER TABLE best_execution_analysis ENABLE ROW LEVEL SECURITY; -- RLS Policies for SOX Trade Audit CREATE POLICY sox_trade_audit_user_policy ON sox_trade_audit FOR ALL TO authenticated_users USING (user_id = current_user_id() OR has_role('admin') OR has_role('compliance_officer') OR has_role('risk_manager')); -- RLS Policies for MiFID II Transaction Report CREATE POLICY mifid_transaction_user_policy ON mifid_transaction_report FOR ALL TO authenticated_users USING (has_role('admin') OR has_role('compliance_officer') OR has_role('trader')); -- RLS Policies for Position Limits CREATE POLICY position_limits_user_policy ON position_limits_audit FOR ALL TO authenticated_users USING (user_id = current_user_id() OR has_role('admin') OR has_role('risk_manager')); -- RLS Policies for Kill Switch (Admin and Risk Managers only) CREATE POLICY kill_switch_restricted_policy ON kill_switch_audit FOR ALL TO authenticated_users USING (has_role('admin') OR has_role('risk_manager')); -- RLS Policies for Best Execution (Compliance officers can see all) CREATE POLICY best_execution_policy ON best_execution_analysis FOR ALL TO authenticated_users USING (has_role('admin') OR has_role('compliance_officer') OR has_role('trader')); -- Functions for SOX Compliance Audit Trail CREATE OR REPLACE FUNCTION log_sox_trade_activity( p_trade_id UUID, p_user_id UUID, p_symbol VARCHAR, p_side VARCHAR, p_quantity DECIMAL, p_price DECIMAL, p_order_type VARCHAR, p_trade_value DECIMAL, p_order_timestamp TIMESTAMP WITH TIME ZONE, p_risk_assessment JSONB DEFAULT NULL, p_compliance_flags JSONB DEFAULT NULL ) RETURNS UUID AS $$ DECLARE v_audit_id UUID; v_audit_hash VARCHAR(64); BEGIN v_audit_id := uuid_generate_v4(); -- Generate audit hash for integrity v_audit_hash := encode( digest( p_trade_id::text || p_user_id::text || p_symbol || p_side || p_quantity::text || p_order_timestamp::text || extract(epoch from now())::text, 'sha256' ), 'hex' ); INSERT INTO sox_trade_audit ( id, trade_id, user_id, symbol, side, quantity, price, order_type, trade_value, order_timestamp, risk_assessment, compliance_flags, audit_hash ) VALUES ( v_audit_id, p_trade_id, p_user_id, p_symbol, p_side, p_quantity, p_price, p_order_type, p_trade_value, p_order_timestamp, p_risk_assessment, p_compliance_flags, v_audit_hash ); RETURN v_audit_id; END; $$ LANGUAGE plpgsql SECURITY DEFINER; -- Function for MiFID II Transaction Reporting CREATE OR REPLACE FUNCTION create_mifid_transaction_report( p_trade_id UUID, p_instrument_id VARCHAR, p_currency VARCHAR, p_price DECIMAL, p_quantity DECIMAL, p_trading_venue VARCHAR, p_transaction_timestamp TIMESTAMP WITH TIME ZONE ) RETURNS UUID AS $$ DECLARE v_report_id UUID; BEGIN v_report_id := uuid_generate_v4(); INSERT INTO mifid_transaction_report ( id, trade_id, instrument_id, currency, price, quantity, trading_venue, transaction_timestamp ) VALUES ( v_report_id, p_trade_id, p_instrument_id, p_currency, p_price, p_quantity, p_trading_venue, p_transaction_timestamp ); RETURN v_report_id; END; $$ LANGUAGE plpgsql SECURITY DEFINER; -- Function for Position Limit Monitoring CREATE OR REPLACE FUNCTION check_position_limits( p_user_id UUID, p_instrument_id VARCHAR, p_position_size DECIMAL, p_position_limit DECIMAL ) RETURNS UUID AS $$ DECLARE v_audit_id UUID; v_utilization DECIMAL; v_is_breach BOOLEAN; v_breach_amount DECIMAL; v_breach_percentage DECIMAL; BEGIN v_audit_id := uuid_generate_v4(); v_utilization := ABS(p_position_size) / ABS(p_position_limit); v_is_breach := v_utilization > 1.0; IF v_is_breach THEN v_breach_amount := ABS(p_position_size) - ABS(p_position_limit); v_breach_percentage := v_utilization - 1.0; END IF; INSERT INTO position_limits_audit ( id, user_id, instrument_id, position_size, position_limit, limit_utilization, is_breach, breach_amount, breach_percentage, position_timestamp ) VALUES ( v_audit_id, p_user_id, p_instrument_id, p_position_size, p_position_limit, v_utilization, v_is_breach, v_breach_amount, v_breach_percentage, NOW() ); RETURN v_audit_id; END; $$ LANGUAGE plpgsql SECURITY DEFINER; -- Function for Kill Switch Activation CREATE OR REPLACE FUNCTION activate_kill_switch( p_switch_type VARCHAR, p_trigger_reason VARCHAR, p_severity_level VARCHAR, p_triggered_by_user UUID DEFAULT NULL, p_portfolio_value DECIMAL DEFAULT NULL, p_daily_pnl DECIMAL DEFAULT NULL ) RETURNS UUID AS $$ DECLARE v_audit_id UUID; BEGIN v_audit_id := uuid_generate_v4(); INSERT INTO kill_switch_audit ( id, switch_type, trigger_reason, severity_level, triggered_by_user, portfolio_value, daily_pnl ) VALUES ( v_audit_id, p_switch_type, p_trigger_reason, p_severity_level, p_triggered_by_user, p_portfolio_value, p_daily_pnl ); -- Log security event PERFORM log_security_event( 'KILL_SWITCH_ACTIVATED', p_triggered_by_user, jsonb_build_object( 'switch_type', p_switch_type, 'severity', p_severity_level, 'reason', p_trigger_reason, 'audit_id', v_audit_id ) ); RETURN v_audit_id; END; $$ LANGUAGE plpgsql SECURITY DEFINER; -- Function for Best Execution Analysis CREATE OR REPLACE FUNCTION analyze_best_execution( p_trade_id UUID, p_primary_venue VARCHAR, p_reference_price DECIMAL, p_execution_price DECIMAL, p_explicit_costs DECIMAL, p_implicit_costs DECIMAL ) RETURNS UUID AS $$ DECLARE v_analysis_id UUID; v_price_improvement DECIMAL; v_price_improvement_pct DECIMAL; v_total_costs DECIMAL; v_overall_score DECIMAL; v_quality_grade VARCHAR(5); v_meets_best_execution BOOLEAN; BEGIN v_analysis_id := uuid_generate_v4(); v_price_improvement := p_reference_price - p_execution_price; v_price_improvement_pct := v_price_improvement / p_reference_price; v_total_costs := p_explicit_costs + p_implicit_costs; -- Calculate overall score (simplified algorithm) v_overall_score := GREATEST(0.0, LEAST(1.0, 0.5 + (v_price_improvement_pct * 2.0) - (v_total_costs / p_execution_price) )); -- Assign quality grade v_quality_grade := CASE WHEN v_overall_score >= 0.95 THEN 'A+' WHEN v_overall_score >= 0.90 THEN 'A' WHEN v_overall_score >= 0.85 THEN 'A-' WHEN v_overall_score >= 0.80 THEN 'B+' WHEN v_overall_score >= 0.75 THEN 'B' WHEN v_overall_score >= 0.70 THEN 'B-' WHEN v_overall_score >= 0.65 THEN 'C+' WHEN v_overall_score >= 0.60 THEN 'C' WHEN v_overall_score >= 0.50 THEN 'C-' WHEN v_overall_score >= 0.40 THEN 'D' ELSE 'F' END; v_meets_best_execution := v_overall_score >= 0.70; INSERT INTO best_execution_analysis ( id, trade_id, primary_venue, reference_price, execution_price, price_improvement_amount, price_improvement_percentage, explicit_costs, implicit_costs, total_transaction_costs, overall_score, execution_quality_grade, meets_best_execution ) VALUES ( v_analysis_id, p_trade_id, p_primary_venue, p_reference_price, p_execution_price, v_price_improvement, v_price_improvement_pct, p_explicit_costs, p_implicit_costs, v_total_costs, v_overall_score, v_quality_grade, v_meets_best_execution ); RETURN v_analysis_id; END; $$ LANGUAGE plpgsql SECURITY DEFINER; -- Triggers for automatic audit trail updates CREATE OR REPLACE FUNCTION update_audit_timestamp() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); NEW.audit_version = OLD.audit_version + 1; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER sox_trade_audit_update_trigger BEFORE UPDATE ON sox_trade_audit FOR EACH ROW EXECUTE FUNCTION update_audit_timestamp(); -- Grant permissions to authenticated users GRANT SELECT, INSERT ON sox_trade_audit TO authenticated_users; GRANT SELECT, INSERT ON mifid_transaction_report TO authenticated_users; GRANT SELECT, INSERT ON position_limits_audit TO authenticated_users; GRANT SELECT, INSERT ON kill_switch_audit TO authenticated_users; GRANT SELECT, INSERT ON best_execution_analysis TO authenticated_users; -- Grant execute permissions on functions GRANT EXECUTE ON FUNCTION log_sox_trade_activity TO authenticated_users; GRANT EXECUTE ON FUNCTION create_mifid_transaction_report TO authenticated_users; GRANT EXECUTE ON FUNCTION check_position_limits TO authenticated_users; GRANT EXECUTE ON FUNCTION activate_kill_switch TO authenticated_users; GRANT EXECUTE ON FUNCTION analyze_best_execution TO authenticated_users; -- Comments for documentation COMMENT ON TABLE sox_trade_audit IS 'SOX compliance audit trail for all trading activities - Section 404 internal controls'; COMMENT ON TABLE mifid_transaction_report IS 'MiFID II transaction reporting - Article 26 regulatory requirements'; COMMENT ON TABLE position_limits_audit IS 'Position limits monitoring - MiFID II Article 57 compliance'; COMMENT ON TABLE kill_switch_audit IS 'Circuit breaker and kill switch audit trail for risk management'; COMMENT ON TABLE best_execution_analysis IS 'Best execution analysis - MiFID II Article 27 compliance'; COMMENT ON FUNCTION log_sox_trade_activity IS 'Creates SOX compliance audit record for trade activity'; COMMENT ON FUNCTION create_mifid_transaction_report IS 'Creates MiFID II transaction report for regulatory submission'; COMMENT ON FUNCTION check_position_limits IS 'Monitors position limits and logs compliance status'; COMMENT ON FUNCTION activate_kill_switch IS 'Activates kill switch and creates audit trail'; COMMENT ON FUNCTION analyze_best_execution IS 'Analyzes trade execution quality for MiFID II compliance';